From 7f5d495f79ff4f69040cbfa4842d78695ab2a885 Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Mon, 25 Mar 2024 16:14:48 +0100 Subject: [PATCH 01/12] 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 c89dddbcc6a..1e4ff2ccaba 100644 --- a/Kitodo/src/main/java/org/kitodo/config/enums/ParameterCore.java +++ b/Kitodo/src/main/java/org/kitodo/config/enums/ParameterCore.java @@ -621,6 +621,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 21837bc7956..3716b60c0e1 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; @@ -109,6 +112,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 0570ff44a0f..b06a024871c 100644 --- a/Kitodo/src/main/resources/kitodo_config.properties +++ b/Kitodo/src/main/resources/kitodo_config.properties @@ -639,6 +639,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 # ----------------------------------- From a2c8b5e2fce3e0f32940cc56f1703895b011845c Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Tue, 26 Mar 2024 12:08:07 +0100 Subject: [PATCH 02/12] Prevent NumberFormatException for blank input string --- .../interfaces/activemq/MapMessageObjectReader.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 3716b60c0e1..659fc074bc6 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 @@ -27,6 +27,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.util.Strings; import org.kitodo.utils.Guard; public class MapMessageObjectReader { @@ -128,8 +129,8 @@ public String getMandatoryString(String key) throws JMSException { 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()); + .flatMap(string -> Arrays.stream(string.split("\\D+"))).filter(Strings::isNotBlank) + .map(Integer::valueOf).collect(Collectors.toList()); return collectionOfInteger; } From 34ac62feaba56a2481f76eba569d86c06db2258e Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Wed, 17 Apr 2024 10:33:28 +0200 Subject: [PATCH 03/12] Update Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/MapMessageObjectReader.java Co-authored-by: Arved Solth --- .../production/interfaces/activemq/MapMessageObjectReader.java | 1 - 1 file changed, 1 deletion(-) 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 659fc074bc6..918251f95e3 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 @@ -16,7 +16,6 @@ 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; From 84568a6cfa831ee5369aa3dfa9a6bc107e61ef31 Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Wed, 24 Apr 2024 11:09:00 +0200 Subject: [PATCH 04/12] Use StringUtils::isNumeric --- .../interfaces/activemq/MapMessageObjectReader.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 918251f95e3..23aa98cf21b 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 @@ -16,6 +16,7 @@ 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; @@ -24,9 +25,9 @@ import javax.jms.JMSException; import javax.jms.MapMessage; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.util.Strings; import org.kitodo.utils.Guard; public class MapMessageObjectReader { @@ -128,7 +129,7 @@ public String getMandatoryString(String key) throws JMSException { public Collection getCollectionOfInteger(String key) throws JMSException { Collection collectionOfString = getCollectionOfString(key); List collectionOfInteger = collectionOfString.stream() - .flatMap(string -> Arrays.stream(string.split("\\D+"))).filter(Strings::isNotBlank) + .flatMap(string -> Arrays.stream(string.split("\\D+"))).filter(StringUtils::isNumeric) .map(Integer::valueOf).collect(Collectors.toList()); return collectionOfInteger; } From f88d9ea5fd906bfb4d138b86b004d354963d870a Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Wed, 24 Apr 2024 11:09:44 +0200 Subject: [PATCH 05/12] Inline return statement --- .../interfaces/activemq/MapMessageObjectReader.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 23aa98cf21b..c7e128f6772 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 @@ -16,7 +16,6 @@ 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; @@ -127,11 +126,9 @@ public String getMandatoryString(String key) throws JMSException { * can be thrown by MapMessage.getObject(String) */ public Collection getCollectionOfInteger(String key) throws JMSException { - Collection collectionOfString = getCollectionOfString(key); - List collectionOfInteger = collectionOfString.stream() + return getCollectionOfString(key).stream() .flatMap(string -> Arrays.stream(string.split("\\D+"))).filter(StringUtils::isNumeric) .map(Integer::valueOf).collect(Collectors.toList()); - return collectionOfInteger; } /** From 4d7f518122b2fb7f8294a3903eccae6088c07581 Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Wed, 24 Apr 2024 12:04:53 +0200 Subject: [PATCH 06/12] Add test for KitodoScriptProcessor --- .../services/command/KitodoScriptService.java | 2 +- .../activemq/KitodoScriptProcessorIT.java | 440 ++++++++++++++++++ 2 files changed, 441 insertions(+), 1 deletion(-) create mode 100644 Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java diff --git a/Kitodo/src/main/java/org/kitodo/production/services/command/KitodoScriptService.java b/Kitodo/src/main/java/org/kitodo/production/services/command/KitodoScriptService.java index 1d7a4e59d61..daef20493a4 100644 --- a/Kitodo/src/main/java/org/kitodo/production/services/command/KitodoScriptService.java +++ b/Kitodo/src/main/java/org/kitodo/production/services/command/KitodoScriptService.java @@ -86,7 +86,7 @@ public static KitodoScriptService getInstance() { /** * Private constructor. Use {@link #getInstance()} to get the instance. */ - private KitodoScriptService() { + protected KitodoScriptService() { } /** diff --git a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java new file mode 100644 index 00000000000..7fb4ee2ef4e --- /dev/null +++ b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java @@ -0,0 +1,440 @@ +/* + * (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 static org.junit.Assert.assertEquals; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MapMessage; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.kitodo.MockDatabase; +import org.kitodo.SecurityTestUtils; +import org.kitodo.data.database.beans.Process; +import org.kitodo.production.services.ServiceManager; +import org.kitodo.production.services.command.KitodoScriptService; + +public class KitodoScriptProcessorIT { + @Before + public void prepare() throws Exception { + MockDatabase.startNode(); + MockDatabase.insertProcessesForWorkflowFull(); + SecurityTestUtils.addUserDataToSecurityContext(ServiceManager.getUserService().getById(1), 1); + } + + @After + public void clean() throws Exception { + MockDatabase.stopNode(); + MockDatabase.cleanDatabase(); + SecurityTestUtils.cleanSecurityContext(); + } + + @Test + public void shouldExecuteKitodoScript() throws Exception { + + // define test data + MapMessageObjectReader testData = new MapMessageObjectReader(new MapMessage() { + @Override + public String getJMSMessageID() throws JMSException { + return null; + } + + @Override + public void setJMSMessageID(String id) throws JMSException { + + } + + @Override + public long getJMSTimestamp() throws JMSException { + return 0; + } + + @Override + public void setJMSTimestamp(long timestamp) throws JMSException { + + } + + @Override + public byte[] getJMSCorrelationIDAsBytes() throws JMSException { + return null; + } + + @Override + public void setJMSCorrelationIDAsBytes(byte[] correlationID) throws JMSException { + + } + + @Override + public void setJMSCorrelationID(String correlationID) throws JMSException { + + } + + @Override + public String getJMSCorrelationID() throws JMSException { + return null; + } + + @Override + public Destination getJMSReplyTo() throws JMSException { + return null; + } + + @Override + public void setJMSReplyTo(Destination replyTo) throws JMSException { + + } + + @Override + public Destination getJMSDestination() throws JMSException { + return null; + } + + @Override + public void setJMSDestination(Destination destination) throws JMSException { + + } + + @Override + public int getJMSDeliveryMode() throws JMSException { + return 0; + } + + @Override + public void setJMSDeliveryMode(int deliveryMode) throws JMSException { + + } + + @Override + public boolean getJMSRedelivered() throws JMSException { + return false; + } + + @Override + public void setJMSRedelivered(boolean redelivered) throws JMSException { + + } + + @Override + public String getJMSType() throws JMSException { + return null; + } + + @Override + public void setJMSType(String type) throws JMSException { + + } + + @Override + public long getJMSExpiration() throws JMSException { + return 0; + } + + @Override + public void setJMSExpiration(long expiration) throws JMSException { + + } + + @Override + public int getJMSPriority() throws JMSException { + return 0; + } + + @Override + public void setJMSPriority(int priority) throws JMSException { + + } + + @Override + public void clearProperties() throws JMSException { + + } + + @Override + public boolean propertyExists(String name) throws JMSException { + return false; + } + + @Override + public boolean getBooleanProperty(String name) throws JMSException { + return false; + } + + @Override + public byte getByteProperty(String name) throws JMSException { + return 0; + } + + @Override + public short getShortProperty(String name) throws JMSException { + return 0; + } + + @Override + public int getIntProperty(String name) throws JMSException { + return 0; + } + + @Override + public long getLongProperty(String name) throws JMSException { + return 0; + } + + @Override + public float getFloatProperty(String name) throws JMSException { + return 0; + } + + @Override + public double getDoubleProperty(String name) throws JMSException { + return 0; + } + + @Override + public String getStringProperty(String name) throws JMSException { + return null; + } + + @Override + public Object getObjectProperty(String name) throws JMSException { + return null; + } + + @Override + public Enumeration getPropertyNames() throws JMSException { + return null; + } + + @Override + public void setBooleanProperty(String name, boolean value) throws JMSException { + + } + + @Override + public void setByteProperty(String name, byte value) throws JMSException { + + } + + @Override + public void setShortProperty(String name, short value) throws JMSException { + + } + + @Override + public void setIntProperty(String name, int value) throws JMSException { + + } + + @Override + public void setLongProperty(String name, long value) throws JMSException { + + } + + @Override + public void setFloatProperty(String name, float value) throws JMSException { + + } + + @Override + public void setDoubleProperty(String name, double value) throws JMSException { + + } + + @Override + public void setStringProperty(String name, String value) throws JMSException { + + } + + @Override + public void setObjectProperty(String name, Object value) throws JMSException { + + } + + @Override + public void acknowledge() throws JMSException { + + } + + @Override + public void clearBody() throws JMSException { + + } + + @Override + public boolean getBoolean(String name) throws JMSException { + return false; + } + + @Override + public byte getByte(String name) throws JMSException { + return 0; + } + + @Override + public short getShort(String name) throws JMSException { + return 0; + } + + @Override + public char getChar(String name) throws JMSException { + return 0; + } + + @Override + public int getInt(String name) throws JMSException { + return 0; + } + + @Override + public long getLong(String name) throws JMSException { + return 0; + } + + @Override + public float getFloat(String name) throws JMSException { + return 0; + } + + @Override + public double getDouble(String name) throws JMSException { + return 0; + } + + @Override + public String getString(String name) throws JMSException { + return null; + } + + @Override + public byte[] getBytes(String name) throws JMSException { + return null; + } + + @Override + public Object getObject(String name) throws JMSException { + return null; + } + + @Override + public Enumeration getMapNames() throws JMSException { + return null; + } + + @Override + public void setBoolean(String name, boolean value) throws JMSException { + + } + + @Override + public void setByte(String name, byte value) throws JMSException { + + } + + @Override + public void setShort(String name, short value) throws JMSException { + + } + + @Override + public void setChar(String name, char value) throws JMSException { + + } + + @Override + public void setInt(String name, int value) throws JMSException { + + } + + @Override + public void setLong(String name, long value) throws JMSException { + + } + + @Override + public void setFloat(String name, float value) throws JMSException { + + } + + @Override + public void setDouble(String name, double value) throws JMSException { + + } + + @Override + public void setString(String name, String value) throws JMSException { + + } + + @Override + public void setBytes(String name, byte[] value) throws JMSException { + + } + + @Override + public void setBytes(String name, byte[] value, int offset, int length) throws JMSException { + + } + + @Override + public void setObject(String name, Object value) throws JMSException { + + } + + @Override + public boolean itemExists(String name) throws JMSException { + return false; + } + }) { + @Override + public String getMandatoryString(String s) { + return "action:test"; + } + + @Override + public Collection getCollectionOfInteger(String s) { + return Collections.singletonList(1); + } + }; + + // the object to be tested + KitodoScriptProcessor underTest = new KitodoScriptProcessor(); + + // organize return of results + List scriptResult = new ArrayList<>(); + List processesResult = new ArrayList<>(); + Field serviceField = KitodoScriptProcessor.class.getDeclaredField("kitodoScriptService"); + serviceField.setAccessible(true); + serviceField.set(underTest, new KitodoScriptService() { + @Override + public void execute(List processes, String script) { + scriptResult.add(script); + processesResult.addAll(processes); + } + }); + + // carry out test + underTest.process(testData); + + // check results + assertEquals("should have passed the script to be executed", scriptResult.get(0), "action:test"); + assertEquals("should have passed one process", processesResult.size(), 1); + assertEquals("should have passed process 1", processesResult.get(0).getId(), (Integer) 1); + } +} From b7c5f2be26986ef9b9844dd02d7509ba8ececa7c Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Thu, 1 Aug 2024 09:47:48 +0200 Subject: [PATCH 07/12] Replace Junit 4 with Junit 5 --- .../activemq/KitodoScriptProcessorIT.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java index 7fb4ee2ef4e..ac6f5121b03 100644 --- a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java +++ b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java @@ -10,7 +10,7 @@ */ package org.kitodo.production.interfaces.activemq; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.lang.reflect.Field; import java.util.ArrayList; @@ -23,9 +23,9 @@ import javax.jms.JMSException; import javax.jms.MapMessage; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.kitodo.MockDatabase; import org.kitodo.SecurityTestUtils; import org.kitodo.data.database.beans.Process; @@ -33,14 +33,14 @@ import org.kitodo.production.services.command.KitodoScriptService; public class KitodoScriptProcessorIT { - @Before + @BeforeAll public void prepare() throws Exception { MockDatabase.startNode(); MockDatabase.insertProcessesForWorkflowFull(); SecurityTestUtils.addUserDataToSecurityContext(ServiceManager.getUserService().getById(1), 1); } - @After + @AfterAll public void clean() throws Exception { MockDatabase.stopNode(); MockDatabase.cleanDatabase(); @@ -433,8 +433,8 @@ public void execute(List processes, String script) { underTest.process(testData); // check results - assertEquals("should have passed the script to be executed", scriptResult.get(0), "action:test"); - assertEquals("should have passed one process", processesResult.size(), 1); - assertEquals("should have passed process 1", processesResult.get(0).getId(), (Integer) 1); + assertEquals(scriptResult.get(0), "action:test", "should have passed the script to be executed"); + assertEquals(processesResult.size(), 1, "should have passed one process"); + assertEquals(processesResult.get(0).getId(), 1, "should have passed process 1"); } } From dea467ce1d4914efee4399a1203a2a1d5269b1cd Mon Sep 17 00:00:00 2001 From: Henning Gerhardt Date: Mon, 5 Aug 2024 14:49:01 +0200 Subject: [PATCH 08/12] Replace BeforeAll/AfterAll with BeforeEach/AfterEach --- .../interfaces/activemq/KitodoScriptProcessorIT.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java index ac6f5121b03..0aa964e7e02 100644 --- a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java +++ b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java @@ -23,8 +23,8 @@ import javax.jms.JMSException; import javax.jms.MapMessage; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.kitodo.MockDatabase; import org.kitodo.SecurityTestUtils; @@ -33,14 +33,14 @@ import org.kitodo.production.services.command.KitodoScriptService; public class KitodoScriptProcessorIT { - @BeforeAll + @BeforeEach public void prepare() throws Exception { MockDatabase.startNode(); MockDatabase.insertProcessesForWorkflowFull(); SecurityTestUtils.addUserDataToSecurityContext(ServiceManager.getUserService().getById(1), 1); } - @AfterAll + @AfterEach public void clean() throws Exception { MockDatabase.stopNode(); MockDatabase.cleanDatabase(); From 7a7ad96753b1d28f384418b12ebd3cdd22852b7a Mon Sep 17 00:00:00 2001 From: Henning Gerhardt Date: Mon, 5 Aug 2024 14:51:45 +0200 Subject: [PATCH 09/12] Use Mockito to create test object --- .../activemq/KitodoScriptProcessorIT.java | 374 +----------------- 1 file changed, 6 insertions(+), 368 deletions(-) diff --git a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java index 0aa964e7e02..07b8c5d0c2d 100644 --- a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java +++ b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java @@ -11,18 +11,14 @@ package org.kitodo.production.interfaces.activemq; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; -import java.util.Enumeration; import java.util.List; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.MapMessage; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -51,367 +47,9 @@ public void clean() throws Exception { public void shouldExecuteKitodoScript() throws Exception { // define test data - MapMessageObjectReader testData = new MapMessageObjectReader(new MapMessage() { - @Override - public String getJMSMessageID() throws JMSException { - return null; - } - - @Override - public void setJMSMessageID(String id) throws JMSException { - - } - - @Override - public long getJMSTimestamp() throws JMSException { - return 0; - } - - @Override - public void setJMSTimestamp(long timestamp) throws JMSException { - - } - - @Override - public byte[] getJMSCorrelationIDAsBytes() throws JMSException { - return null; - } - - @Override - public void setJMSCorrelationIDAsBytes(byte[] correlationID) throws JMSException { - - } - - @Override - public void setJMSCorrelationID(String correlationID) throws JMSException { - - } - - @Override - public String getJMSCorrelationID() throws JMSException { - return null; - } - - @Override - public Destination getJMSReplyTo() throws JMSException { - return null; - } - - @Override - public void setJMSReplyTo(Destination replyTo) throws JMSException { - - } - - @Override - public Destination getJMSDestination() throws JMSException { - return null; - } - - @Override - public void setJMSDestination(Destination destination) throws JMSException { - - } - - @Override - public int getJMSDeliveryMode() throws JMSException { - return 0; - } - - @Override - public void setJMSDeliveryMode(int deliveryMode) throws JMSException { - - } - - @Override - public boolean getJMSRedelivered() throws JMSException { - return false; - } - - @Override - public void setJMSRedelivered(boolean redelivered) throws JMSException { - - } - - @Override - public String getJMSType() throws JMSException { - return null; - } - - @Override - public void setJMSType(String type) throws JMSException { - - } - - @Override - public long getJMSExpiration() throws JMSException { - return 0; - } - - @Override - public void setJMSExpiration(long expiration) throws JMSException { - - } - - @Override - public int getJMSPriority() throws JMSException { - return 0; - } - - @Override - public void setJMSPriority(int priority) throws JMSException { - - } - - @Override - public void clearProperties() throws JMSException { - - } - - @Override - public boolean propertyExists(String name) throws JMSException { - return false; - } - - @Override - public boolean getBooleanProperty(String name) throws JMSException { - return false; - } - - @Override - public byte getByteProperty(String name) throws JMSException { - return 0; - } - - @Override - public short getShortProperty(String name) throws JMSException { - return 0; - } - - @Override - public int getIntProperty(String name) throws JMSException { - return 0; - } - - @Override - public long getLongProperty(String name) throws JMSException { - return 0; - } - - @Override - public float getFloatProperty(String name) throws JMSException { - return 0; - } - - @Override - public double getDoubleProperty(String name) throws JMSException { - return 0; - } - - @Override - public String getStringProperty(String name) throws JMSException { - return null; - } - - @Override - public Object getObjectProperty(String name) throws JMSException { - return null; - } - - @Override - public Enumeration getPropertyNames() throws JMSException { - return null; - } - - @Override - public void setBooleanProperty(String name, boolean value) throws JMSException { - - } - - @Override - public void setByteProperty(String name, byte value) throws JMSException { - - } - - @Override - public void setShortProperty(String name, short value) throws JMSException { - - } - - @Override - public void setIntProperty(String name, int value) throws JMSException { - - } - - @Override - public void setLongProperty(String name, long value) throws JMSException { - - } - - @Override - public void setFloatProperty(String name, float value) throws JMSException { - - } - - @Override - public void setDoubleProperty(String name, double value) throws JMSException { - - } - - @Override - public void setStringProperty(String name, String value) throws JMSException { - - } - - @Override - public void setObjectProperty(String name, Object value) throws JMSException { - - } - - @Override - public void acknowledge() throws JMSException { - - } - - @Override - public void clearBody() throws JMSException { - - } - - @Override - public boolean getBoolean(String name) throws JMSException { - return false; - } - - @Override - public byte getByte(String name) throws JMSException { - return 0; - } - - @Override - public short getShort(String name) throws JMSException { - return 0; - } - - @Override - public char getChar(String name) throws JMSException { - return 0; - } - - @Override - public int getInt(String name) throws JMSException { - return 0; - } - - @Override - public long getLong(String name) throws JMSException { - return 0; - } - - @Override - public float getFloat(String name) throws JMSException { - return 0; - } - - @Override - public double getDouble(String name) throws JMSException { - return 0; - } - - @Override - public String getString(String name) throws JMSException { - return null; - } - - @Override - public byte[] getBytes(String name) throws JMSException { - return null; - } - - @Override - public Object getObject(String name) throws JMSException { - return null; - } - - @Override - public Enumeration getMapNames() throws JMSException { - return null; - } - - @Override - public void setBoolean(String name, boolean value) throws JMSException { - - } - - @Override - public void setByte(String name, byte value) throws JMSException { - - } - - @Override - public void setShort(String name, short value) throws JMSException { - - } - - @Override - public void setChar(String name, char value) throws JMSException { - - } - - @Override - public void setInt(String name, int value) throws JMSException { - - } - - @Override - public void setLong(String name, long value) throws JMSException { - - } - - @Override - public void setFloat(String name, float value) throws JMSException { - - } - - @Override - public void setDouble(String name, double value) throws JMSException { - - } - - @Override - public void setString(String name, String value) throws JMSException { - - } - - @Override - public void setBytes(String name, byte[] value) throws JMSException { - - } - - @Override - public void setBytes(String name, byte[] value, int offset, int length) throws JMSException { - - } - - @Override - public void setObject(String name, Object value) throws JMSException { - - } - - @Override - public boolean itemExists(String name) throws JMSException { - return false; - } - }) { - @Override - public String getMandatoryString(String s) { - return "action:test"; - } - - @Override - public Collection getCollectionOfInteger(String s) { - return Collections.singletonList(1); - } - }; + MapMessageObjectReader mockedMappedMessageObjectReader = mock(MapMessageObjectReader.class); + when(mockedMappedMessageObjectReader.getMandatoryString("script")).thenReturn("action:test"); + when(mockedMappedMessageObjectReader.getCollectionOfInteger("processes")).thenReturn(Collections.singletonList(1)); // the object to be tested KitodoScriptProcessor underTest = new KitodoScriptProcessor(); @@ -430,7 +68,7 @@ public void execute(List processes, String script) { }); // carry out test - underTest.process(testData); + underTest.process(mockedMappedMessageObjectReader); // check results assertEquals(scriptResult.get(0), "action:test", "should have passed the script to be executed"); From 6130bff66ba80a9b0992b0f53fdfb780bd5bc135 Mon Sep 17 00:00:00 2001 From: Henning Gerhardt Date: Mon, 5 Aug 2024 15:05:40 +0200 Subject: [PATCH 10/12] Use Mockito power to mock the KitodoScript execution --- .../services/command/KitodoScriptService.java | 2 +- .../activemq/KitodoScriptProcessorIT.java | 56 +++++++++++++------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Kitodo/src/main/java/org/kitodo/production/services/command/KitodoScriptService.java b/Kitodo/src/main/java/org/kitodo/production/services/command/KitodoScriptService.java index daef20493a4..1d7a4e59d61 100644 --- a/Kitodo/src/main/java/org/kitodo/production/services/command/KitodoScriptService.java +++ b/Kitodo/src/main/java/org/kitodo/production/services/command/KitodoScriptService.java @@ -86,7 +86,7 @@ public static KitodoScriptService getInstance() { /** * Private constructor. Use {@link #getInstance()} to get the instance. */ - protected KitodoScriptService() { + private KitodoScriptService() { } /** diff --git a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java index 07b8c5d0c2d..b950090454c 100644 --- a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java +++ b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java @@ -8,27 +8,45 @@ * 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 static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.platform.commons.util.ReflectionUtils; import org.kitodo.MockDatabase; import org.kitodo.SecurityTestUtils; import org.kitodo.data.database.beans.Process; import org.kitodo.production.services.ServiceManager; import org.kitodo.production.services.command.KitodoScriptService; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.junit.jupiter.MockitoExtension; +@ExtendWith(MockitoExtension.class) public class KitodoScriptProcessorIT { + + @Captor + private ArgumentCaptor> processCaptor; + + @Captor + private ArgumentCaptor scriptCaptor; + @BeforeEach public void prepare() throws Exception { MockDatabase.startNode(); @@ -54,25 +72,31 @@ public void shouldExecuteKitodoScript() throws Exception { // the object to be tested KitodoScriptProcessor underTest = new KitodoScriptProcessor(); - // organize return of results - List scriptResult = new ArrayList<>(); - List processesResult = new ArrayList<>(); - Field serviceField = KitodoScriptProcessor.class.getDeclaredField("kitodoScriptService"); - serviceField.setAccessible(true); - serviceField.set(underTest, new KitodoScriptService() { - @Override - public void execute(List processes, String script) { - scriptResult.add(script); - processesResult.addAll(processes); - } - }); + // manipulate static field to insert a mocked service + // using MockStatic or other options did not work or too less knowdlegde to manipulate a static field + KitodoScriptService kitodoScriptService = mock(KitodoScriptService.class); + Field field = ReflectionUtils + .findFields( + KitodoScriptProcessor.class, f -> f.getName().equals("kitodoScriptService"), + ReflectionUtils.HierarchyTraversalMode.TOP_DOWN) + .get(0); + field.setAccessible(true); + field.set(underTest, kitodoScriptService); + + // capture the method parameters of the execute method + doNothing().when(kitodoScriptService).execute(processCaptor.capture(), scriptCaptor.capture()); // carry out test underTest.process(mockedMappedMessageObjectReader); + // check executed mocks + verify(mockedMappedMessageObjectReader, times(1)).getMandatoryString("script"); + verify(mockedMappedMessageObjectReader, times(1)).getCollectionOfInteger("processes"); + verify(kitodoScriptService, times(1)).execute(anyList(), anyString()); + // check results - assertEquals(scriptResult.get(0), "action:test", "should have passed the script to be executed"); - assertEquals(processesResult.size(), 1, "should have passed one process"); - assertEquals(processesResult.get(0).getId(), 1, "should have passed process 1"); + assertEquals("action:test", scriptCaptor.getValue(), "should have passed the script to be executed"); + assertEquals(1, processCaptor.getAllValues().size(), "should have passed one process"); + assertEquals(1, processCaptor.getAllValues().get(0).get(0).getId(), "should have passed process 1"); } } From a360f5442aec5029fa0479ac8290b55e0d5a3224 Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Wed, 14 Aug 2024 09:46:48 +0200 Subject: [PATCH 11/12] Introduce a whitelist for KitodoScripts --- .../org/kitodo/config/enums/ParameterCore.java | 2 ++ .../activemq/KitodoScriptProcessor.java | 8 ++++++++ .../src/main/resources/kitodo_config.properties | 4 ++++ .../activemq/KitodoScriptProcessorIT.java | 17 +++++++++++++++++ .../src/test/resources/kitodo_config.properties | 2 ++ 5 files changed, 33 insertions(+) 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 1e4ff2ccaba..29ea0699e9e 100644 --- a/Kitodo/src/main/java/org/kitodo/config/enums/ParameterCore.java +++ b/Kitodo/src/main/java/org/kitodo/config/enums/ParameterCore.java @@ -621,6 +621,8 @@ public enum ParameterCore implements ParameterInterface { ACTIVE_MQ_FINALIZE_STEP_QUEUE(new Parameter("activeMQ.finalizeStep.queue")), + ACTIVE_MQ_KITODO_SCRIPT_ALLOW(new Parameter("activeMQ.kitodoScript.allow")), + ACTIVE_MQ_KITODO_SCRIPT_QUEUE(new Parameter("activeMQ.kitodoScript.queue")), ACTIVE_MQ_TASK_ACTION_QUEUE(new Parameter("activeMQ.taskAction.queue")), 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 index 8c3eadeba42..3c2d250b549 100644 --- a/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessor.java +++ b/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessor.java @@ -13,6 +13,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -47,8 +48,15 @@ public KitodoScriptProcessor() { @Override protected void process(MapMessageObjectReader ticket) throws ProcessorException, JMSException { + final List allowedCommands = Arrays.asList(ConfigCore.getParameter( + ParameterCore.ACTIVE_MQ_KITODO_SCRIPT_ALLOW).split(",")); try { String script = ticket.getMandatoryString("script"); + int space = script.indexOf(' '); + if (!allowedCommands.contains(script.substring(7, space >= 0 ? space : script.length()))) { + throw new IllegalArgumentException((space >= 0 ? script.substring(0, space) : script) + + " is not allowed"); + } Collection processIds = ticket.getCollectionOfInteger("processes"); List processes = new ArrayList<>(processIds.size()); for (Integer id : processIds) { diff --git a/Kitodo/src/main/resources/kitodo_config.properties b/Kitodo/src/main/resources/kitodo_config.properties index b06a024871c..00086205493 100644 --- a/Kitodo/src/main/resources/kitodo_config.properties +++ b/Kitodo/src/main/resources/kitodo_config.properties @@ -642,6 +642,10 @@ activeMQ.user=testAdmin # You can provide a queue from which messages are read to run a Kitodo Script #activeMQ.kitodoScript.queue=KitodoProduction.KitodoScript.Queue +# The Kitodo Script commands authorized to be executed must be named here: +activeMQ.kitodoScript.allow=createFolders,export,searchForMedia + + # ----------------------------------- # Elasticsearch properties # ----------------------------------- diff --git a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java index b950090454c..4329189a81f 100644 --- a/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java +++ b/Kitodo/src/test/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessorIT.java @@ -12,6 +12,7 @@ package org.kitodo.production.interfaces.activemq; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.anyList; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doNothing; @@ -99,4 +100,20 @@ public void shouldExecuteKitodoScript() throws Exception { assertEquals(1, processCaptor.getAllValues().size(), "should have passed one process"); assertEquals(1, processCaptor.getAllValues().get(0).get(0).getId(), "should have passed process 1"); } + + @Test + public void shouldNotExecuteKitodoScript() throws Exception { + // test data + MapMessageObjectReader mockedMessage = mock(MapMessageObjectReader.class); + when(mockedMessage.getMandatoryString("script")).thenReturn("action:other"); + + // the object to be tested + KitodoScriptProcessor underTest = new KitodoScriptProcessor(); + + // carry out test + IllegalArgumentException illegalArgumentException = assertThrows(IllegalArgumentException.class, () -> underTest + .process(mockedMessage)); + assertEquals("action:other is not allowed", illegalArgumentException.getMessage(), + "should report that the action is not permitted"); + } } diff --git a/Kitodo/src/test/resources/kitodo_config.properties b/Kitodo/src/test/resources/kitodo_config.properties index 0ab62453b40..722caef0073 100644 --- a/Kitodo/src/test/resources/kitodo_config.properties +++ b/Kitodo/src/test/resources/kitodo_config.properties @@ -54,6 +54,8 @@ metsEditor.lockingTime=2 #copyData.onExport=/@GoobiIdentifier \= $process.id; +activeMQ.kitodoScript.allow=test,test2 + LongTermPreservationValidation.mapping.FALSE.FALSE=ERROR LongTermPreservationValidation.mapping.FALSE.TRUE=ERROR LongTermPreservationValidation.mapping.FALSE.UNDETERMINED=ERROR From d52fceed87ca40994a121ca6476fe7227a19e906 Mon Sep 17 00:00:00 2001 From: Matthias Ronge Date: Wed, 14 Aug 2024 14:40:10 +0200 Subject: [PATCH 12/12] Read allowed scripts from array --- .../interfaces/activemq/KitodoScriptProcessor.java | 7 ++++--- Kitodo/src/main/resources/kitodo_config.properties | 2 +- Kitodo/src/test/resources/kitodo_config.properties | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) 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 index 3c2d250b549..d9924126585 100644 --- a/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessor.java +++ b/Kitodo/src/main/java/org/kitodo/production/interfaces/activemq/KitodoScriptProcessor.java @@ -19,6 +19,7 @@ import javax.jms.JMSException; +import org.apache.commons.lang3.ArrayUtils; import org.kitodo.config.ConfigCore; import org.kitodo.config.enums.ParameterCore; import org.kitodo.data.database.beans.Process; @@ -48,12 +49,12 @@ public KitodoScriptProcessor() { @Override protected void process(MapMessageObjectReader ticket) throws ProcessorException, JMSException { - final List allowedCommands = Arrays.asList(ConfigCore.getParameter( - ParameterCore.ACTIVE_MQ_KITODO_SCRIPT_ALLOW).split(",")); + final String[] allowedCommands = ConfigCore.getStringArrayParameter( + ParameterCore.ACTIVE_MQ_KITODO_SCRIPT_ALLOW); try { String script = ticket.getMandatoryString("script"); int space = script.indexOf(' '); - if (!allowedCommands.contains(script.substring(7, space >= 0 ? space : script.length()))) { + if (!ArrayUtils.contains(allowedCommands, script.substring(7, space >= 0 ? space : script.length()))) { throw new IllegalArgumentException((space >= 0 ? script.substring(0, space) : script) + " is not allowed"); } diff --git a/Kitodo/src/main/resources/kitodo_config.properties b/Kitodo/src/main/resources/kitodo_config.properties index 00086205493..22b3a1f0b0a 100644 --- a/Kitodo/src/main/resources/kitodo_config.properties +++ b/Kitodo/src/main/resources/kitodo_config.properties @@ -643,7 +643,7 @@ activeMQ.user=testAdmin #activeMQ.kitodoScript.queue=KitodoProduction.KitodoScript.Queue # The Kitodo Script commands authorized to be executed must be named here: -activeMQ.kitodoScript.allow=createFolders,export,searchForMedia +activeMQ.kitodoScript.allow=createFolders&export&searchForMedia # ----------------------------------- diff --git a/Kitodo/src/test/resources/kitodo_config.properties b/Kitodo/src/test/resources/kitodo_config.properties index 722caef0073..7c6bdbfa4a3 100644 --- a/Kitodo/src/test/resources/kitodo_config.properties +++ b/Kitodo/src/test/resources/kitodo_config.properties @@ -54,7 +54,7 @@ metsEditor.lockingTime=2 #copyData.onExport=/@GoobiIdentifier \= $process.id; -activeMQ.kitodoScript.allow=test,test2 +activeMQ.kitodoScript.allow=test&test2 LongTermPreservationValidation.mapping.FALSE.FALSE=ERROR LongTermPreservationValidation.mapping.FALSE.TRUE=ERROR