diff --git a/.mvn/maven.config b/.mvn/maven.config index b102b0e7b83..0a656548c59 100644 --- a/.mvn/maven.config +++ b/.mvn/maven.config @@ -2,6 +2,5 @@ --errors --show-version --no-transfer-progress --DinstallAtEnd=true -DdeployAtEnd=true -Duser.timezone=Europe/Berlin diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a742bc5fa7..ae6a8ceb889 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,8 +69,8 @@ An entire repository can be built by running `mvn clean install` in the root dir This will build all sub modules and execute unit tests. Furthermore, you can restrict the build to just the module you are changing by running the same command in the corresponding directory. Check the repository's or module's README for additional module-specific instructions. -The `webapps` and `swagger-ui` modules requires NodeJS. -You can exclude building them by running `mvn clean install -pl '!webapps,!webapps/assembly,!webapps/assembly-jakarta,!org.operaton.bpm.run:operaton-bpm-run-modules-swaggerui'`. +The `webapps` module requires NodeJS. +You can exclude building them by running `mvn clean install -pl '!webapps,!webapps/assembly,!webapps/assembly-jakarta'`. Integration tests (e.g. tests that run in an actual application server) are usually not part of the default Maven profiles. If you think they are relevant to your contribution, please ask us in the ticket, on the forum or in your pull request for how to run them. Smaller contributions usually do not need this. diff --git a/bom/operaton-only-bom/pom.xml b/bom/operaton-only-bom/pom.xml index 7d242edb0e7..a7358dd69bc 100644 --- a/bom/operaton-only-bom/pom.xml +++ b/bom/operaton-only-bom/pom.xml @@ -179,6 +179,11 @@ operaton-bpm-spring-boot-starter-webapp ${project.version} + + org.operaton.bpm.springboot + operaton-bpm-spring-boot-starter-security + ${project.version} + org.operaton.bpm.springboot operaton-bpm-spring-boot-starter-webapp-ee diff --git a/clients/java/client/pom.xml b/clients/java/client/pom.xml index c6bc5cebeff..52023d4a020 100644 --- a/clients/java/client/pom.xml +++ b/clients/java/client/pom.xml @@ -14,7 +14,6 @@ - 5.3 ${project.build.directory}/operaton-tomcat ${engine.runtime}/server/apache-tomcat-${version.tomcat} ${tomcat.connector.http.port} @@ -66,7 +65,7 @@ org.apache.httpcomponents.client5 httpclient5 - ${version.httpclient} + ${version.httpclient5} diff --git a/clients/java/client/src/it/java/org/operaton/bpm/client/variable/FileSerializationIT.java b/clients/java/client/src/it/java/org/operaton/bpm/client/variable/FileSerializationIT.java index fa1f4444c33..5d00f4b8529 100644 --- a/clients/java/client/src/it/java/org/operaton/bpm/client/variable/FileSerializationIT.java +++ b/clients/java/client/src/it/java/org/operaton/bpm/client/variable/FileSerializationIT.java @@ -32,10 +32,12 @@ import org.operaton.bpm.client.util.RecordingExternalTaskHandler; import org.operaton.bpm.client.util.RecordingInvocationHandler; import org.operaton.bpm.client.util.RecordingInvocationHandler.RecordedInvocation; +import org.operaton.bpm.client.variable.impl.value.DeferredFileValueImpl; import org.operaton.bpm.client.variable.value.DeferredFileValue; import org.operaton.bpm.engine.variable.Variables; import org.operaton.bpm.engine.variable.value.FileValue; import org.operaton.bpm.engine.variable.value.TypedValue; +import org.operaton.bpm.model.bpmn.Bpmn; import org.operaton.bpm.model.bpmn.BpmnModelInstance; import org.operaton.commons.utils.IoUtil; @@ -64,6 +66,8 @@ public class FileSerializationIT { protected static final String VARIABLE_NAME_FILE = "fileVariable"; protected static final String VARIABLE_VALUE_FILE_NAME = "aFileName.txt"; protected static final byte[] VARIABLE_VALUE_FILE_VALUE = "ABC".getBytes(); + protected static final String LOCAL_VARIABLE_NAME_FILE = "localFileName.txt"; + protected static final String VARIABLE_VALUE_FILE_ENCODING = "UTF-8"; protected static final String VARIABLE_VALUE_FILE_MIME_TYPE = "text/plain"; @@ -114,6 +118,41 @@ public void shouldGet() { .isEqualTo(new String(VARIABLE_VALUE_FILE_VALUE)); } + @Test + public void shouldGetLocalAndGlobalVariables() { + // given + ProcessDefinitionDto processDefinitionDto = engineRule.deploy( + Bpmn.createExecutableProcess("process") + .startEvent("startEvent") + .serviceTask("serviceTaskFoo") + .operatonExternalTask(EXTERNAL_TASK_TOPIC_FOO) + // create the local file variable with the same content but different name + .operatonInputParameter(LOCAL_VARIABLE_NAME_FILE, "${execution.getVariableTyped('fileVariable')}") + .serviceTask("serviceTaskBar") + .operatonExternalTask(EXTERNAL_TASK_TOPIC_BAR) + .endEvent("endEvent") + .done() + ).get(0); + + engineRule.startProcessInstance(processDefinitionDto.getId(), VARIABLE_NAME_FILE, VARIABLE_VALUE_FILE); + + // when + client.subscribe(EXTERNAL_TASK_TOPIC_FOO) + .handler(handler) + .open(); + + clientRule.waitForFetchAndLockUntil(() -> !handler.getHandledTasks().isEmpty()); + + ExternalTask task = handler.getHandledTasks().get(0); + + // then + assertThat(task.getAllVariables().size()).isEqualTo(2); + assertThat(IoUtil.inputStreamAsString(task.getVariable(VARIABLE_NAME_FILE))) + .isEqualTo(new String(VARIABLE_VALUE_FILE_VALUE)); + assertThat(IoUtil.inputStreamAsString(task.getVariable(LOCAL_VARIABLE_NAME_FILE))) + .isEqualTo(new String(VARIABLE_VALUE_FILE_VALUE)); + } + @Test public void shouldGetAll() { // given @@ -142,7 +181,9 @@ public void shouldGetAll() { @Test public void shouldGetTyped_Deferred() { // given - engineRule.startProcessInstance(processDefinition.getId(), VARIABLE_NAME_FILE, VARIABLE_VALUE_FILE); + ProcessInstanceDto processInstanceDto = engineRule.startProcessInstance(processDefinition.getId(), + VARIABLE_NAME_FILE, + VARIABLE_VALUE_FILE); client.subscribe(EXTERNAL_TASK_TOPIC_FOO) .handler(handler) @@ -160,6 +201,48 @@ public void shouldGetTyped_Deferred() { assertThat(typedValue.isLoaded()).isFalse(); assertThat(typedValue.getEncoding()).isNull(); assertThat(typedValue.getMimeType()).isNull(); + + DeferredFileValueImpl typedValueImpl = (DeferredFileValueImpl) typedValue; + assertThat(typedValueImpl.getExecutionId()).isEqualTo(task.getExecutionId()); + } + + @Test + public void shouldGetVariableTypedForLocalVariable() { + // given + ProcessDefinitionDto processDefinitionDto = engineRule.deploy( + Bpmn.createExecutableProcess("process") + .startEvent("startEvent") + .serviceTask("serviceTaskFoo") + .operatonExternalTask(EXTERNAL_TASK_TOPIC_FOO) + // create the local file variable with the same content but different name + .operatonInputParameter(LOCAL_VARIABLE_NAME_FILE, "${execution.getVariableTyped('fileVariable')}") + .serviceTask("serviceTaskBar") + .operatonExternalTask(EXTERNAL_TASK_TOPIC_BAR) + .endEvent("endEvent") + .done() + ).get(0); + + engineRule.startProcessInstance(processDefinitionDto.getId(), VARIABLE_NAME_FILE, VARIABLE_VALUE_FILE); + + // when + client.subscribe(EXTERNAL_TASK_TOPIC_FOO) + .handler(handler) + .open(); + + clientRule.waitForFetchAndLockUntil(() -> !handler.getHandledTasks().isEmpty()); + + ExternalTask task = handler.getHandledTasks().get(0); + + // then + DeferredFileValue typedValue = task.getVariableTyped(LOCAL_VARIABLE_NAME_FILE); + assertThat(typedValue.getFilename()).isEqualTo(VARIABLE_VALUE_FILE_NAME); + assertThat(typedValue.getType()).isEqualTo(FILE); + assertThat(typedValue.isLoaded()).isFalse(); + assertThat(typedValue.getEncoding()).isNull(); + assertThat(typedValue.getMimeType()).isNull(); + + InputStream value = typedValue.getValue(); + assertThat(IoUtil.inputStreamAsString(value)).isEqualTo(new String(VARIABLE_VALUE_FILE_VALUE)); } @Test diff --git a/clients/java/client/src/main/java/org/operaton/bpm/client/impl/EngineClient.java b/clients/java/client/src/main/java/org/operaton/bpm/client/impl/EngineClient.java index 43e4b3a49bb..927aed3cb5c 100644 --- a/clients/java/client/src/main/java/org/operaton/bpm/client/impl/EngineClient.java +++ b/clients/java/client/src/main/java/org/operaton/bpm/client/impl/EngineClient.java @@ -52,11 +52,10 @@ public class EngineClient { public static final String FAILURE_RESOURCE_PATH = ID_RESOURCE_PATH + "/failure"; public static final String BPMN_ERROR_RESOURCE_PATH = ID_RESOURCE_PATH + "/bpmnError"; public static final String NAME_PATH_PARAM = "{name}"; - public static final String EXECUTION_RESOURCE_PATH = "/execution"; - public static final String EXECUTION_ID_RESOURCE_PATH = EXECUTION_RESOURCE_PATH + "/" + ID_PATH_PARAM; - public static final String GET_LOCAL_VARIABLE = EXECUTION_ID_RESOURCE_PATH + "/localVariables/" + NAME_PATH_PARAM; - public static final String GET_LOCAL_BINARY_VARIABLE = GET_LOCAL_VARIABLE + "/data"; - + public static final String PROCESS_INSTANCE_RESOURCE_PATH = "/process-instance"; + public static final String PROCESS_INSTANCE_ID_RESOURCE_PATH = PROCESS_INSTANCE_RESOURCE_PATH + "/" + ID_PATH_PARAM; + public static final String GET_BINARY_VARIABLE = + PROCESS_INSTANCE_ID_RESOURCE_PATH + "/variables/" + NAME_PATH_PARAM + "/data"; protected String baseUrl; protected String workerId; protected int maxTasks; @@ -147,9 +146,9 @@ public void extendLock(String taskId, long newDuration) { engineInteraction.postRequest(resourceUrl, payload, Void.class); } - public byte[] getLocalBinaryVariable(String variableName, String processInstanceId) { - String resourcePath = baseUrl + GET_LOCAL_BINARY_VARIABLE - .replace(ID_PATH_PARAM, processInstanceId) + public byte[] getLocalBinaryVariable(String variableName, String executionId) { + String resourcePath = baseUrl + GET_BINARY_VARIABLE + .replace(ID_PATH_PARAM, executionId) .replace(NAME_PATH_PARAM, variableName); return engineInteraction.getRequest(resourcePath); diff --git a/clients/java/client/src/main/java/org/operaton/bpm/client/variable/impl/TypedValues.java b/clients/java/client/src/main/java/org/operaton/bpm/client/variable/impl/TypedValues.java index 4310c29cb1a..fa7de42fe16 100644 --- a/clients/java/client/src/main/java/org/operaton/bpm/client/variable/impl/TypedValues.java +++ b/clients/java/client/src/main/java/org/operaton/bpm/client/variable/impl/TypedValues.java @@ -69,7 +69,7 @@ public Map serializeVariables(Map varia @SuppressWarnings("rawtypes") public Map wrapVariables(ExternalTask externalTask, Map variables) { - String processInstanceId = externalTask.getProcessInstanceId(); + String executionId = externalTask.getExecutionId(); Map result = new HashMap<>(); @@ -80,7 +80,7 @@ public Map wrapVariables(ExternalTask externalTask, Map { - protected String processInstanceId; + protected String executionId; protected String variableName; protected TypedValueField typedValueField; protected ValueMappers mappers; @@ -30,8 +30,8 @@ public class VariableValue { protected ValueMapper serializer; protected T cachedValue; - public VariableValue(String processInstanceId, String variableName, TypedValueField typedValueField, ValueMappers mappers) { - this.processInstanceId = processInstanceId; + public VariableValue(String executionId, String variableName, TypedValueField typedValueField, ValueMappers mappers) { + this.executionId = executionId; this.variableName = variableName; this.typedValueField = typedValueField; this.mappers = mappers; @@ -63,7 +63,7 @@ public T getTypedValue(boolean deserializeValue) { if (cachedValue instanceof DeferredFileValueImpl) { DeferredFileValueImpl fileValue = (DeferredFileValueImpl) cachedValue; - fileValue.setProcessInstanceId(processInstanceId); + fileValue.setExecutionId(executionId); fileValue.setVariableName(variableName); } } @@ -83,7 +83,7 @@ public ValueMapper getSerializer() { public String toString() { return "VariableValue [" + "cachedValue=" + cachedValue + ", " - + "processInstanceId=" + processInstanceId + ", " + + "executionId=" + executionId + ", " + "variableName=" + variableName + ", " + "typedValueField=" + typedValueField + "]"; } diff --git a/clients/java/client/src/main/java/org/operaton/bpm/client/variable/impl/value/DeferredFileValueImpl.java b/clients/java/client/src/main/java/org/operaton/bpm/client/variable/impl/value/DeferredFileValueImpl.java index ba83d17c056..a9c7ac4f6f9 100644 --- a/clients/java/client/src/main/java/org/operaton/bpm/client/variable/impl/value/DeferredFileValueImpl.java +++ b/clients/java/client/src/main/java/org/operaton/bpm/client/variable/impl/value/DeferredFileValueImpl.java @@ -37,7 +37,7 @@ public class DeferredFileValueImpl extends FileValueImpl implements DeferredFile protected boolean isLoaded = false; protected String variableName; - protected String processInstanceId; + protected String executionId; protected EngineClient engineClient; public DeferredFileValueImpl(String filename, EngineClient engineClient) { @@ -47,7 +47,7 @@ public DeferredFileValueImpl(String filename, EngineClient engineClient) { protected void load() { try { - byte[] bytes = engineClient.getLocalBinaryVariable(variableName, processInstanceId); + byte[] bytes = engineClient.getLocalBinaryVariable(variableName, executionId); setValue(bytes); this.isLoaded = true; @@ -71,17 +71,22 @@ public InputStream getValue() { return super.getValue(); } - public void setProcessInstanceId(String processInstanceId) { - this.processInstanceId = processInstanceId; - } - public void setVariableName(String variableName) { this.variableName = variableName; } + public void setExecutionId(String executionId){ + this.executionId = executionId; + }; + + public String getExecutionId() { + return executionId; + } + @Override public String toString() { - return "DeferredFileValueImpl [mimeType=" + mimeType + ", filename=" + filename + ", type=" + type + ", isTransient=" + isTransient + ", isLoaded=" + isLoaded + "]"; + return "DeferredFileValueImpl [mimeType=" + mimeType + ", filename=" + filename + ", type=" + type + ", " + + "isTransient=" + isTransient + ", isLoaded=" + isLoaded + "]"; } } diff --git a/clients/java/client/src/test/java/org/operaton/bpm/client/task/ExternalTaskImplTest.java b/clients/java/client/src/test/java/org/operaton/bpm/client/task/ExternalTaskImplTest.java index a9a5b3beafb..1c8025207e6 100644 --- a/clients/java/client/src/test/java/org/operaton/bpm/client/task/ExternalTaskImplTest.java +++ b/clients/java/client/src/test/java/org/operaton/bpm/client/task/ExternalTaskImplTest.java @@ -139,8 +139,8 @@ void shouldDisplayAttributesIncludingMapsInToString() { task.setWorkerId("wi"); Map receivedVariables = new LinkedHashMap<>(); - receivedVariables.put("rv1", generateVariableValue("pii", "variable1", ValueType.STRING.getName(), "value1", 42, "vi2")); - receivedVariables.put("rv2", generateVariableValue("pii", "variable2", ValueType.INTEGER.getName(), 99, 42, "vi2", 87L)); + receivedVariables.put("rv1", generateVariableValue(task.getExecutionId(), "variable1", ValueType.STRING.getName(), "value1", 42, "vi2")); + receivedVariables.put("rv2", generateVariableValue(task.getExecutionId(), "variable2", ValueType.INTEGER.getName(), 99, 42, "vi2", 87L)); task.setReceivedVariableMap(receivedVariables); Map variables = new LinkedHashMap<>(); @@ -163,9 +163,9 @@ void shouldDisplayAttributesIncludingMapsInToString() { + "processDefinitionVersionTag=versionTag, " + "processInstanceId=pii, " + "receivedVariableMap={" - + "rv1=VariableValue [cachedValue=null, processInstanceId=pii, variableName=variable1, typedValueField=" + + "rv1=VariableValue [cachedValue=null, executionId=ei, variableName=variable1, typedValueField=" + "TypedValueField [type=string, value=value1, valueInfo={vi1=42, vi2=vi2}]], " - + "rv2=VariableValue [cachedValue=null, processInstanceId=pii, variableName=variable2, typedValueField=" + + "rv2=VariableValue [cachedValue=null, executionId=ei, variableName=variable2, typedValueField=" + "TypedValueField [type=integer, value=99, valueInfo={vi1=42, vi2=vi2, vi3=87}]]" + "}, " + "retries=34, " @@ -184,10 +184,10 @@ void shouldDisplayAttributesIncludingMapsInToString() { private static final ValueMappers DEFAULT_MAPPERS = new DefaultValueMappers(Variables.SerializationDataFormats.JSON.getName()); @SuppressWarnings("rawtypes") - private static VariableValue generateVariableValue(String processInstanceId, String variableName, + private static VariableValue generateVariableValue(String executionId, String variableName, final String typeI, final Object valueI, Object... valueInfos) { TypedValueField typedValueField = generateTypedValueField(typeI, valueI, valueInfos); - return new VariableValue(processInstanceId, variableName, typedValueField, DEFAULT_MAPPERS); + return new VariableValue(executionId, variableName, typedValueField, DEFAULT_MAPPERS); } private static TypedValueField generateTypedValueField(final String typeI, final Object valueI, Object... valueInfos) { diff --git a/database/pom.xml b/database/pom.xml index 082192f20ce..8ee94a7c920 100644 --- a/database/pom.xml +++ b/database/pom.xml @@ -24,7 +24,7 @@ 1.1.8 8.3.0 8.4.1.jre8 - 11.5.0.0 + 11.5.9.0 ${version.db2-11.5} 42.5.5 4.8.0 diff --git a/distro/run/assembly/assembly.xml b/distro/run/assembly/assembly.xml index 0d08b498d68..aaf88cd03f0 100644 --- a/distro/run/assembly/assembly.xml +++ b/distro/run/assembly/assembly.xml @@ -19,6 +19,13 @@ ${artifact.artifactId}.${artifact.extension} + + internal/oauth2/ + + org.operaton.bpm.run:operaton-bpm-run-modules-oauth2 + + ${artifact.artifactId}.${artifact.extension} + internal/example/ @@ -122,6 +129,10 @@ ../modules/rest/target/dependency/ internal/rest/ + + ../modules/oauth2/target/dependency/ + internal/oauth2/ + resources/dummyResource diff --git a/distro/run/assembly/pom.xml b/distro/run/assembly/pom.xml index 18b1a2e9172..6163b802528 100644 --- a/distro/run/assembly/pom.xml +++ b/distro/run/assembly/pom.xml @@ -49,6 +49,21 @@ + + + org.operaton.bpm.run + operaton-bpm-run-modules-oauth2 + ${project.version} + jar + + + + * + * + + + + org.operaton.bpm.run operaton-bpm-run-modules-example-invoice diff --git a/distro/run/assembly/resources/default.yml b/distro/run/assembly/resources/default.yml index 2a98cd5ca6e..c4ff0cff027 100644 --- a/distro/run/assembly/resources/default.yml +++ b/distro/run/assembly/resources/default.yml @@ -13,6 +13,10 @@ operaton.bpm: cors: enabled: true allowed-origins: "*" + rest: + disable-wadl: false + deployment: + deploy-changed-only: true # https://docs.operaton.org/manual/latest/user-guide/operaton-bpm-run/#example-application example: enabled: true diff --git a/distro/run/assembly/resources/production.yml b/distro/run/assembly/resources/production.yml index 26f10a79d03..a447064986b 100644 --- a/distro/run/assembly/resources/production.yml +++ b/distro/run/assembly/resources/production.yml @@ -29,6 +29,8 @@ operaton.bpm: # https://docs.operaton.org/manual/latest/user-guide/security/#authentication # https://docs.operaton.org/manual/latest/user-guide/operaton-bpm-run/#authentication auth.enabled: true + rest.disable-wadl: true + deployment.deploy-changed-only: true # https://docs.operaton.org/manual/latest/user-guide/process-engine/identity-service/#configuration-properties-of-the-ldap-plugin # https://docs.operaton.org/manual/latest/user-guide/operaton-bpm-run/#ldap-identity-service # Uncomment this section to enable LDAP support for Operaton Run diff --git a/distro/run/assembly/resources/run.bat b/distro/run/assembly/resources/run.bat index b17b03bcdf5..f4b0d43017a 100644 --- a/distro/run/assembly/resources/run.bat +++ b/distro/run/assembly/resources/run.bat @@ -5,6 +5,7 @@ SET BASEDIR=%~dp0 SET PARENTDIR=%BASEDIR%..\ SET DEPLOYMENTDIR=%PARENTDIR%configuration/resources SET WEBAPPS_PATH=%BASEDIR%webapps +SET OAUTH2_PATH=%BASEDIR%oauth2 SET REST_PATH=%BASEDIR%rest SET EXAMPLE_PATH=%BASEDIR%example SET APPNAME=Operaton Run @@ -79,6 +80,12 @@ IF [%~1]==[--webapps] ( ECHO WebApps enabled ) +IF [%~1]==[--oauth2] ( + SET optionalComponentChosen=true + SET classPath=%OAUTH2_PATH%,%classPath% + ECHO Spring Security OAuth2 enabled +) + IF [%~1]==[--rest] ( SET optionalComponentChosen=true SET restChosen=true @@ -159,6 +166,7 @@ ECHO Usage: run.bat [start^|stop] (options...) :ArgsHelp ECHO Options: ECHO --webapps - Enables the Operaton Webapps +ECHO --oauth2 - Enables the Operaton Platform Spring Security OAuth2 integration ECHO --rest - Enables the REST API ECHO --example - Enables the example application ECHO --production - Applies the production.yaml configuration file diff --git a/distro/run/assembly/resources/run.sh b/distro/run/assembly/resources/run.sh index bd2612553a0..1db9420bce6 100644 --- a/distro/run/assembly/resources/run.sh +++ b/distro/run/assembly/resources/run.sh @@ -5,11 +5,13 @@ BASEDIR=$(dirname "$0") PARENTDIR=$(builtin cd "$BASEDIR/.."; pwd) DEPLOYMENT_DIR=$PARENTDIR/configuration/resources WEBAPPS_PATH=$BASEDIR/webapps/ +OAUTH2_PATH=$BASEDIR/oauth2/ REST_PATH=$BASEDIR/rest/ EXAMPLE_PATH=$BASEDIR/example PID_PATH=$BASEDIR/run.pid OPTIONS_HELP="Options: --webapps - Enables the Operaton Webapps + --oauth2 - Enables the Operaton Platform Spring Security OAuth2 integration --rest - Enables the REST API --example - Enables the example application --production - Applies the production.yaml configuration file @@ -57,6 +59,10 @@ if [ "$1" = "start" ] ; then classPath=$WEBAPPS_PATH,$classPath echo WebApps enabled ;; + --oauth2 ) optionalComponentChosen=true + classPath=$OAUTH2_PATH,$classPath + echo Spring Security OAuth2 enabled + ;; --rest ) optionalComponentChosen=true restChosen=true classPath=$REST_PATH,$classPath @@ -76,7 +82,10 @@ if [ "$1" = "start" ] ; then --help ) printf "%s" "$OPTIONS_HELP" exit 0 ;; - * ) exit 1 + * ) printf "Unexpected argument '%s'!" "$1" + printf "%s" "$OPTIONS_HELP" + exit 1 + ;; esac shift done diff --git a/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunConfiguration.java b/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunConfiguration.java index 21c2a73321b..0d8e9652e40 100644 --- a/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunConfiguration.java +++ b/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunConfiguration.java @@ -16,64 +16,55 @@ */ package org.operaton.bpm.run; -import java.util.List; -import java.util.Map; - -import org.operaton.bpm.engine.impl.cfg.CompositeProcessEnginePlugin; import org.operaton.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.operaton.bpm.engine.impl.cfg.ProcessEnginePlugin; import org.operaton.bpm.engine.impl.plugin.AdministratorAuthorizationPlugin; -import org.operaton.bpm.engine.spring.SpringProcessEngineConfiguration; import org.operaton.bpm.identity.impl.ldap.plugin.LdapIdentityProviderPlugin; import org.operaton.bpm.run.property.OperatonBpmRunAdministratorAuthorizationProperties; import org.operaton.bpm.run.property.OperatonBpmRunLdapProperties; -import org.operaton.bpm.run.property.OperatonBpmRunProcessEnginePluginProperty; import org.operaton.bpm.run.property.OperatonBpmRunProperties; -import org.operaton.bpm.run.utils.OperatonBpmRunProcessEnginePluginHelper; import org.operaton.bpm.spring.boot.starter.OperatonBpmAutoConfiguration; -import org.operaton.bpm.spring.boot.starter.configuration.OperatonDeploymentConfiguration; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.List; + @EnableConfigurationProperties(OperatonBpmRunProperties.class) @Configuration @AutoConfigureAfter({ OperatonBpmAutoConfiguration.class }) public class OperatonBpmRunConfiguration { - @Autowired - OperatonBpmRunProperties operatonBpmRunProperties; - @Bean @ConditionalOnProperty(name = "enabled", havingValue = "true", prefix = OperatonBpmRunLdapProperties.PREFIX) - public LdapIdentityProviderPlugin ldapIdentityProviderPlugin() { - return operatonBpmRunProperties.getLdap(); + public LdapIdentityProviderPlugin ldapIdentityProviderPlugin(OperatonBpmRunProperties properties) { + return properties.getLdap(); } @Bean @ConditionalOnProperty(name = "enabled", havingValue = "true", prefix = OperatonBpmRunAdministratorAuthorizationProperties.PREFIX) - public AdministratorAuthorizationPlugin administratorAuthorizationPlugin() { - return operatonBpmRunProperties.getAdminAuth(); + public AdministratorAuthorizationPlugin administratorAuthorizationPlugin(OperatonBpmRunProperties properties) { + return properties.getAdminAuth(); } @Bean - public ProcessEngineConfigurationImpl processEngineConfigurationImpl(List processEnginePlugins) { - final SpringProcessEngineConfiguration configuration = new OperatonBpmRunProcessEngineConfiguration(); - - // register process engine plugins defined in yaml - List yamlPluginsInfo = operatonBpmRunProperties.getProcessEnginePlugins(); - OperatonBpmRunProcessEnginePluginHelper.registerYamlPlugins(processEnginePlugins, yamlPluginsInfo); + public ProcessEngineConfigurationImpl processEngineConfigurationImpl(List processEnginePluginsFromContext, + OperatonBpmRunProperties properties, + OperatonBpmRunDeploymentConfiguration deploymentConfig) { + String normalizedDeploymentDir = deploymentConfig.getNormalizedDeploymentDir(); + boolean deployChangedOnly = properties.getDeployment().isDeployChangedOnly(); + var processEnginePluginsFromYaml = properties.getProcessEnginePlugins(); - configuration.getProcessEnginePlugins().add(new CompositeProcessEnginePlugin(processEnginePlugins)); - return configuration; + return new OperatonBpmRunProcessEngineConfiguration(normalizedDeploymentDir, deployChangedOnly, + processEnginePluginsFromContext, processEnginePluginsFromYaml); } @Bean - public static OperatonDeploymentConfiguration operatonDeploymentConfiguration() { - return new OperatonBpmRunDeploymentConfiguration(); + public OperatonBpmRunDeploymentConfiguration operatonDeploymentConfiguration(@Value("${operaton.deploymentDir:#{null}}") String deploymentDir) { + return new OperatonBpmRunDeploymentConfiguration(deploymentDir); } } diff --git a/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunDeploymentConfiguration.java b/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunDeploymentConfiguration.java index 1fb24482e84..464ddd82228 100644 --- a/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunDeploymentConfiguration.java +++ b/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunDeploymentConfiguration.java @@ -16,6 +16,12 @@ */ package org.operaton.bpm.run; +import org.apache.commons.lang3.StringUtils; +import org.operaton.bpm.spring.boot.starter.configuration.impl.DefaultDeploymentConfiguration; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -25,23 +31,16 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; -import org.operaton.bpm.spring.boot.starter.configuration.impl.DefaultDeploymentConfiguration; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; - public class OperatonBpmRunDeploymentConfiguration extends DefaultDeploymentConfiguration { - public static final String CAMUNDA_DEPLOYMENT_DIR_PROPERTY = "operaton.deploymentDir"; + private final String deploymentDir; - @Autowired - private Environment env; + public OperatonBpmRunDeploymentConfiguration(String deploymentDir) { + this.deploymentDir = deploymentDir; + } @Override public Set getDeploymentResources() { - String deploymentDir = env.getProperty(CAMUNDA_DEPLOYMENT_DIR_PROPERTY); if (!StringUtils.isEmpty(deploymentDir)) { Path resourceDir = Paths.get(deploymentDir); @@ -53,4 +52,13 @@ public Set getDeploymentResources() { } return Collections.emptySet(); } + + protected String getNormalizedDeploymentDir() { + String result = deploymentDir; + + if(File.separator.equals("\\")) { + result = result.replace("\\", "/"); + } + return result; + } } \ No newline at end of file diff --git a/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunProcessEngineConfiguration.java b/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunProcessEngineConfiguration.java index b6bcfdd52bf..6e44fd0ac44 100644 --- a/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunProcessEngineConfiguration.java +++ b/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunProcessEngineConfiguration.java @@ -16,25 +16,31 @@ */ package org.operaton.bpm.run; -import jakarta.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.util.Set; - import org.operaton.bpm.engine.ProcessEngineException; +import org.operaton.bpm.engine.impl.cfg.CompositeProcessEnginePlugin; +import org.operaton.bpm.engine.impl.cfg.ProcessEnginePlugin; import org.operaton.bpm.engine.impl.diagnostics.OperatonIntegration; import org.operaton.bpm.engine.spring.SpringProcessEngineConfiguration; -import org.springframework.core.env.Environment; +import org.operaton.bpm.run.property.OperatonBpmRunProcessEnginePluginProperty; +import org.operaton.bpm.run.utils.OperatonBpmRunProcessEnginePluginHelper; import org.springframework.core.io.Resource; +import java.io.IOException; +import java.util.List; +import java.util.Set; + public class OperatonBpmRunProcessEngineConfiguration extends SpringProcessEngineConfiguration { + private final String normalizedDeploymentDir; - @Inject - private Environment env; + public OperatonBpmRunProcessEngineConfiguration(String normalizedDeploymentDir, + boolean deployChangedOnly, + List processEnginePluginsFromContext, + List processEnginePluginsFromYaml) { + this.normalizedDeploymentDir = normalizedDeploymentDir; - public OperatonBpmRunProcessEngineConfiguration() { - setDeployChangedOnly(true); + setDeployChangedOnly(deployChangedOnly); + configureProcessEnginePlugins(processEnginePluginsFromContext, processEnginePluginsFromYaml); } @Override @@ -42,12 +48,8 @@ protected String getFileResourceName(Resource resource) { // only path relative to the root deployment directory as identifier to // prevent re-deployments when the path changes (e.g. distro is moved) try { - String deploymentDir = env.getProperty(OperatonBpmRunDeploymentConfiguration.CAMUNDA_DEPLOYMENT_DIR_PROPERTY); - if(File.separator.equals("\\")) { - deploymentDir = deploymentDir.replace("\\", "/"); - } String resourceAbsolutePath = resource.getURI().toString(); - int startIndex = resourceAbsolutePath.indexOf(deploymentDir) + deploymentDir.length(); + int startIndex = resourceAbsolutePath.indexOf(normalizedDeploymentDir) + normalizedDeploymentDir.length(); return resourceAbsolutePath.substring(startIndex); } catch (IOException e) { throw new ProcessEngineException("Failed to locate resource " + resource.getFilename(), e); @@ -60,4 +62,12 @@ protected void initTelemetryData() { Set operatonIntegration = telemetryData.getProduct().getInternals().getOperatonIntegration(); operatonIntegration.add(OperatonIntegration.CAMUNDA_BPM_RUN); } + + protected void configureProcessEnginePlugins(List processEnginePluginsFromContext, + List processEnginePluginsFromYaml) { + // register process engine plugins defined in yaml + OperatonBpmRunProcessEnginePluginHelper.registerYamlPlugins(processEnginePluginsFromContext, processEnginePluginsFromYaml); + + this.processEnginePlugins.add(new CompositeProcessEnginePlugin(processEnginePluginsFromContext)); + } } diff --git a/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunRestConfiguration.java b/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunRestConfiguration.java index 0e899608d26..3a1c16b4be5 100644 --- a/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunRestConfiguration.java +++ b/distro/run/core/src/main/java/org/operaton/bpm/run/OperatonBpmRunRestConfiguration.java @@ -24,6 +24,7 @@ import org.operaton.bpm.run.property.OperatonBpmRunProperties; import org.operaton.bpm.spring.boot.starter.OperatonBpmAutoConfiguration; import org.operaton.bpm.spring.boot.starter.rest.OperatonBpmRestInitializer; +import org.operaton.bpm.spring.boot.starter.rest.OperatonJerseyResourceConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -34,6 +35,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.Collections; + @EnableConfigurationProperties(OperatonBpmRunProperties.class) @Configuration @AutoConfigureAfter({ OperatonBpmAutoConfiguration.class }) @@ -106,4 +109,11 @@ public FilterRegistrationBean corsFilter(JerseyApplicationPath applicati return registration; } + @Bean + public OperatonJerseyResourceConfig operatonRunJerseyResourceConfig() { + OperatonJerseyResourceConfig operatonJerseyResourceConfig = new OperatonJerseyResourceConfig(); + operatonJerseyResourceConfig.setProperties(Collections.singletonMap("jersey.config.server.wadl.disableWadl", operatonBpmRunProperties.getRest().isDisableWadl())); + return operatonJerseyResourceConfig; + } + } diff --git a/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunDeploymentProperties.java b/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunDeploymentProperties.java new file mode 100644 index 00000000000..972bf25876e --- /dev/null +++ b/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunDeploymentProperties.java @@ -0,0 +1,37 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.operaton.bpm.run.property; + +public class OperatonBpmRunDeploymentProperties { + + public static final String PREFIX = OperatonBpmRunProperties.PREFIX + ".deployment"; + + protected boolean deployChangedOnly = true; + + public boolean isDeployChangedOnly() { + return deployChangedOnly; + } + + public void setDeployChangedOnly(boolean deployChangedOnly) { + this.deployChangedOnly = deployChangedOnly; + } + + @Override + public String toString() { + return "OperatonBpmRunDeploymentProperties[" + "deployChangedOnly=" + deployChangedOnly + ']'; + } +} diff --git a/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunProcessEnginePluginProperty.java b/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunProcessEnginePluginProperty.java index 1572e1a9732..115a97777b8 100644 --- a/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunProcessEnginePluginProperty.java +++ b/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunProcessEnginePluginProperty.java @@ -17,7 +17,6 @@ package org.operaton.bpm.run.property; import java.util.Collections; -import java.util.HashMap; import java.util.Map; public class OperatonBpmRunProcessEnginePluginProperty { diff --git a/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunProperties.java b/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunProperties.java index c3527fa28b9..c8903e905df 100644 --- a/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunProperties.java +++ b/distro/run/core/src/main/java/org/operaton/bpm/run/property/OperatonBpmRunProperties.java @@ -16,15 +16,13 @@ */ package org.operaton.bpm.run.property; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.operaton.bpm.spring.boot.starter.property.OperatonBpmProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; +import java.util.ArrayList; +import java.util.List; + @ConfigurationProperties(OperatonBpmRunProperties.PREFIX) public class OperatonBpmRunProperties { @@ -42,6 +40,12 @@ public class OperatonBpmRunProperties { @NestedConfigurationProperty protected List processEnginePlugins = new ArrayList<>(); + @NestedConfigurationProperty + protected OperatonBpmRunRestProperties rest = new OperatonBpmRunRestProperties(); + + @NestedConfigurationProperty + protected OperatonBpmRunDeploymentProperties deployment = new OperatonBpmRunDeploymentProperties(); + protected OperatonBpmRunAdministratorAuthorizationProperties adminAuth = new OperatonBpmRunAdministratorAuthorizationProperties(); @@ -85,6 +89,23 @@ public void setProcessEnginePlugins(List response = testRestTemplate.getForEntity(CONTEXT_PATH + "/application.wadl", JsonNode.class); + + // then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().get("message").textValue()).isEqualTo("HTTP 404 Not Found"); + assertThat(response.getBody().get("type").textValue()).isEqualTo("NotFoundException"); + assertThat(response.getBody().get("code").getNodeType()).isEqualTo(JsonNodeType.NULL); + } +} \ No newline at end of file diff --git a/distro/run/core/src/test/java/org/operaton/bpm/run/test/config/rest/WadlEnabledTest.java b/distro/run/core/src/test/java/org/operaton/bpm/run/test/config/rest/WadlEnabledTest.java new file mode 100644 index 00000000000..e024714e74f --- /dev/null +++ b/distro/run/core/src/test/java/org/operaton/bpm/run/test/config/rest/WadlEnabledTest.java @@ -0,0 +1,42 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.operaton.bpm.run.test.config.rest; + +import org.operaton.bpm.run.property.OperatonBpmRunRestProperties; +import org.operaton.bpm.run.test.AbstractRestTest; +import org.junit.Test; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestPropertySource(properties = { OperatonBpmRunRestProperties.PREFIX + ".disable-wadl=false" }) +public class WadlEnabledTest extends AbstractRestTest { + + @Test + public void shouldReturnWadl() { + // given + + // when + ResponseEntity response = testRestTemplate.getForEntity(CONTEXT_PATH + "/application.wadl", String.class); + + // then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotEmpty(); + } +} \ No newline at end of file diff --git a/distro/run/core/src/test/java/org/operaton/bpm/run/test/config/rest/WadlUnsetTest.java b/distro/run/core/src/test/java/org/operaton/bpm/run/test/config/rest/WadlUnsetTest.java new file mode 100644 index 00000000000..5006c9661bf --- /dev/null +++ b/distro/run/core/src/test/java/org/operaton/bpm/run/test/config/rest/WadlUnsetTest.java @@ -0,0 +1,39 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.operaton.bpm.run.test.config.rest; + +import org.operaton.bpm.run.test.AbstractRestTest; +import org.junit.Test; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.assertj.core.api.Assertions.assertThat; + +public class WadlUnsetTest extends AbstractRestTest { + + @Test + public void shouldReturnWadl() { + // given + + // when + ResponseEntity response = testRestTemplate.getForEntity(CONTEXT_PATH + "/application.wadl", String.class); + + // then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotEmpty(); + } +} \ No newline at end of file diff --git a/distro/run/modules/oauth2/pom.xml b/distro/run/modules/oauth2/pom.xml new file mode 100644 index 00000000000..21c13db8fb9 --- /dev/null +++ b/distro/run/modules/oauth2/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + org.operaton.bpm.run + operaton-bpm-run-modules + 1.0.0-beta-2 + .. + + + operaton-bpm-run-modules-oauth2 + Operaton Platform - Run - Module Spring Security + jar + + + + false + + + + + + org.operaton.bpm.springboot + operaton-bpm-spring-boot-starter-security + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + + \ No newline at end of file diff --git a/distro/run/modules/oauth2/src/main/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSpringSecurityDisableAutoConfiguration.java b/distro/run/modules/oauth2/src/main/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSpringSecurityDisableAutoConfiguration.java new file mode 100644 index 00000000000..53d0ace690b --- /dev/null +++ b/distro/run/modules/oauth2/src/main/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSpringSecurityDisableAutoConfiguration.java @@ -0,0 +1,40 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.operaton.bpm.spring.boot.starter.security; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.SecurityFilterChain; + +public class OperatonBpmSpringSecurityDisableAutoConfiguration { + + private static final Logger logger = LoggerFactory.getLogger(OperatonBpmSpringSecurityDisableAutoConfiguration.class); + + @Bean + public SecurityFilterChain filterChainPermitAll(HttpSecurity http) throws Exception { + logger.info("Disabling Operaton Spring Security oauth2 integration"); + + http.authorizeHttpRequests(customizer -> customizer.anyRequest().permitAll()) + .cors(AbstractHttpConfigurer::disable) + .csrf(AbstractHttpConfigurer::disable); + return http.build(); + } + +} diff --git a/distro/run/modules/oauth2/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/distro/run/modules/oauth2/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..1a45bc3236b --- /dev/null +++ b/distro/run/modules/oauth2/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.operaton.bpm.spring.boot.starter.security.OperatonBpmSpringSecurityDisableAutoConfiguration \ No newline at end of file diff --git a/distro/run/pom.xml b/distro/run/pom.xml index 5b51c84fbe0..dc729ca55b5 100644 --- a/distro/run/pom.xml +++ b/distro/run/pom.xml @@ -80,6 +80,7 @@ modules/webapps + modules/oauth2 distro qa diff --git a/distro/run/qa/integration-tests/src/test/java/org/operaton/bpm/run/qa/ComponentAvailabilityIT.java b/distro/run/qa/integration-tests/src/test/java/org/operaton/bpm/run/qa/ComponentAvailabilityIT.java index ce4946f2fad..c92dbc606f7 100644 --- a/distro/run/qa/integration-tests/src/test/java/org/operaton/bpm/run/qa/ComponentAvailabilityIT.java +++ b/distro/run/qa/integration-tests/src/test/java/org/operaton/bpm/run/qa/ComponentAvailabilityIT.java @@ -57,7 +57,8 @@ public static Collection commands() { { new String[]{"--rest", "--example"}, true, false, true }, { new String[]{"--webapps"}, false, true, false }, { new String[]{"--rest", "--webapps"}, true, true, false }, - { new String[]{"--rest", "--webapps", "--example"}, true, true, true } + { new String[]{"--rest", "--webapps", "--example"}, true, true, true }, + { new String[]{"--rest", "--webapps", "--example", "--oauth2"}, true, true, true } }); } diff --git a/distro/tomcat/assembly/assembly.xml b/distro/tomcat/assembly/assembly.xml index a896496ae50..7d8e8bbb04c 100644 --- a/distro/tomcat/assembly/assembly.xml +++ b/distro/tomcat/assembly/assembly.xml @@ -111,6 +111,7 @@ org.operaton.bpm.model:*:jar org.operaton.bpm.dmn:*:jar + org.operaton.bpm.juel:*:jar org.camunda.feel:*:jar diff --git a/engine-rest/engine-rest-openapi/src/main/templates/lib/commons/history-process-instance.ftl b/engine-rest/engine-rest-openapi/src/main/templates/lib/commons/history-process-instance.ftl index d24f16bb978..d5532b1cf92 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/lib/commons/history-process-instance.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/lib/commons/history-process-instance.ftl @@ -123,6 +123,12 @@ "desc": "Only include process instances which have a root incident. Value may only be `true`, as `false` is the default behavior." }, + "incidentIdIn": { + "type": "array", + "itemType": "string", + "desc": "Restrict to instances that have an incident with one of the given ids. ${listTypeDescription}" + }, + "incidentType": { "type": "string", "desc": "Filter by the incident type. See the [User Guide](${docsUrl}/user-guide/process-engine/incidents/#incident-types) for a list of incident types." @@ -231,6 +237,12 @@ "desc": "Only include historic process instances which belong to no tenant. Value may only be `true`, as `false` is the default behavior." }, + "activityIdIn": { + "type": "array", + "itemType": "string", + "desc": "Restrict to instances with an active activity with one of the given ids. This filter behaves differently as `activeActivityIdIn` since it also yields results when filtering for activities with an incident. ${listTypeDescription}" + }, + "executedActivityIdIn": { "type": "array", "itemType": "string", diff --git a/engine-rest/engine-rest-openapi/src/main/templates/lib/commons/task-query-params.ftl b/engine-rest/engine-rest-openapi/src/main/templates/lib/commons/task-query-params.ftl index 81cbdedf485..1b5bc1e646d 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/lib/commons/task-query-params.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/lib/commons/task-query-params.ftl @@ -200,6 +200,11 @@ type = "string" desc = "Only include tasks that are offered to the given group." /> + <@lib.parameter name = "candidateGroupLike" + location = "query" + type = "string" + desc = "Only include tasks that are offered to groups that have the parameter value as a substring." /> + <@lib.parameter name = "candidateGroupExpression" location = "query" type = "string" @@ -657,5 +662,15 @@ <@lib.parameter name = "parentTaskId" location = "query" type = "string" + desc = "Restrict query to all tasks that are sub tasks of the given task. Takes a task id." /> + + <@lib.parameter name = "withCommentAttachmentInfo" + location = "query" + type = "boolean" + defaultValue = "false" last = last - desc = "Restrict query to all tasks that are sub tasks of the given task. Takes a task id." /> \ No newline at end of file + desc = "Check if task has attachments and/or comments. Value may only be `true`, as + `false` is the default behavior. + Adding the filter will do additional attachment and comments queries to the database, + it might slow down the query in case of tables having high volume of data. + This param is not considered for count queries" /> \ No newline at end of file diff --git a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/ModificationDto.ftl b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/ModificationDto.ftl index cdbbb46d552..94d6b54fe5f 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/ModificationDto.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/ModificationDto.ftl @@ -37,6 +37,14 @@ desc = "A process instance query." /> + <@lib.property + name = "historicProcessInstanceQuery" + type = "ref" + dto = "HistoricProcessInstanceQueryDto" + desc = "A historic process instance query. It is advised to include the `unfinished` filter in the + historic process instance query as finished instances cause failures for the modification." + /> + <@lib.property name = "instructions" type = "array" diff --git a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/MultiFormDeploymentDto.ftl b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/MultiFormDeploymentDto.ftl index 10e40a77388..4e3f8e26eb3 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/MultiFormDeploymentDto.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/MultiFormDeploymentDto.ftl @@ -17,7 +17,7 @@ defaultValue = 'false' desc = "A flag indicating whether the process engine should perform duplicate checking on a per-resource basis. If set to true, only those resources that have actually changed are deployed. - Checks are made against resources included previous deployments of the same name and only against the latest versions of those resources. + Checks are made against resources included previous deployments of the same name and source and only against the latest versions of those resources. If set to true, the option enable-duplicate-filtering is overridden and set to true." /> <@lib.property diff --git a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/history/HistoricJobLogDto.ftl b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/history/HistoricJobLogDto.ftl index 067f3393b38..8a74373c63b 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/history/HistoricJobLogDto.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/history/HistoricJobLogDto.ftl @@ -140,7 +140,17 @@ The name of the host of the Process Engine where the job of this historic job log entry was executed." /> - + + <@lib.property + name = "batchId" + type = "string" + desc = "The ID of the batch associated with this job. `null` if no batch is associated with this job. The + following jobs are associated with batches: + * Seed Jobs + * Monitor Jobs + * Batch Execution Jobs" + /> + <@lib.property name = "creationLog" type = "boolean" diff --git a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceDto.ftl b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceDto.ftl index 6a47adab83e..3ff9134d65f 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceDto.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceDto.ftl @@ -101,7 +101,6 @@ name = "state" type = "string" enumValues = ["ACTIVE", "SUSPENDED", "COMPLETED", "EXTERNALLY_TERMINATED", "INTERNALLY_TERMINATED"] - last = true desc = "Last state of the process instance, possible values are: `ACTIVE` - running process instance @@ -114,5 +113,11 @@ `INTERNALLY_TERMINATED` - terminated internally, for instance by terminating boundary event"/> + <@lib.property + name = "restartedProcessInstanceId" + type = "string" + desc = "The id of the original process instance which was restarted." + last = true /> + \ No newline at end of file diff --git a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/JobDto.ftl b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/JobDto.ftl index 8c998351497..aead833b674 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/JobDto.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/JobDto.ftl @@ -90,6 +90,16 @@ type = "string" format = "date-time" desc = "The date on which this job has been created." + /> + + <@lib.property + name = "batchId" + type = "string" + desc = "The ID of the batch associated with this job. `null` if no batch is associated with this job. The + following jobs are associated with batches: + * Seed Jobs + * Monitor Jobs + * Batch Execution Jobs" last = true /> diff --git a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/task/TaskQueryDto.ftl b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/task/TaskQueryDto.ftl index 49bc2365d85..ae8783555e6 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/task/TaskQueryDto.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/task/TaskQueryDto.ftl @@ -208,6 +208,11 @@ name = "candidateGroup" type = "string" desc = "Only include tasks that are offered to the given group." /> + + <@lib.property + name = "candidateGroupLike" + type = "string" + desc = "Only include tasks that are offered to groups that have the parameter value as a substring." /> <@lib.property name = "candidateGroupExpression" diff --git a/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/task/TaskWithAttachmentAndCommentDto.ftl b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/task/TaskWithAttachmentAndCommentDto.ftl new file mode 100644 index 00000000000..5b6b13ff4ad --- /dev/null +++ b/engine-rest/engine-rest-openapi/src/main/templates/models/org/operaton/bpm/engine/rest/dto/runtime/task/TaskWithAttachmentAndCommentDto.ftl @@ -0,0 +1,17 @@ +<#macro dto_macro docsUrl=""> +<@lib.dto + extends = "TaskDto" > + + <@lib.property + name = "attachment" + type = "boolean" + desc = "Specifies if an attachment exists for the task." /> + + <@lib.property + name = "comment" + type = "boolean" + last = true + desc = "Specifies if an comment exists for the task." /> + + + \ No newline at end of file diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/external-task/fetchAndLock/post.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/external-task/fetchAndLock/post.ftl index 379a5d12964..9c236360571 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/external-task/fetchAndLock/post.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/external-task/fetchAndLock/post.ftl @@ -70,7 +70,7 @@ "sorting": [ { "sortBy":"createTime", - "sortOrder":"ASC" + "sortOrder":"asc" } ] } diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/get.ftl index c8bccee0981..46704735371 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/get.ftl @@ -58,6 +58,7 @@ "rootProcessInstanceId": "aRootProcessInstanceId", "tenantId": null, "hostname": "aHostname", + "batchId": "aBatchId", "creationLog": true, "failureLog": false, "successLog": false, diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/post.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/post.ftl index 89474fb00c7..f257c2fcb0b 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/post.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/post.ftl @@ -63,6 +63,7 @@ "rootProcessInstanceId": "aRootProcessInstanceId", "tenantId": null, "hostname": "aHostname", + "batchId": "aBatchId", "creationLog": true, "failureLog": false, "successLog": false, diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/{id}/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/{id}/get.ftl index 982b19cb195..b1499c48b3b 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/{id}/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/job-log/{id}/get.ftl @@ -52,6 +52,7 @@ "rootProcessInstanceId": "aRootProcessInstanceId", "tenantId": null, "hostname": "aHostname", + "batchId": "aBatchId", "creationLog": true, "failureLog": false, "successLog": false, diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/get.ftl index c3ba6c8843e..e315a9842e8 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/get.ftl @@ -53,7 +53,8 @@ "superCaseInstanceId":null, "caseInstanceId":null, "tenantId":null, - "state":"ACTIVE" + "state":"ACTIVE", + "restartedProcessInstanceId":"2bef365d-3406-11ef-bd73-0a0027000003" } ] }'] /> diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/post.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/post.ftl index ecbfa354206..4a1ff6e53cc 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/post.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/post.ftl @@ -78,7 +78,8 @@ "superCaseInstanceId":null, "caseInstanceId":null, "tenantId":null, - "state":"ACTIVE" + "state":"ACTIVE", + "restartedProcessInstanceId":"2bef365d-3406-11ef-bd73-0a0027000003" } ] }'] /> diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/{id}/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/{id}/get.ftl index 8cb0e8f502a..e26e84a4490 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/{id}/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/history/process-instance/{id}/get.ftl @@ -46,7 +46,8 @@ "superCaseInstanceId":null, "caseInstanceId":null, "tenantId":null, - "state":"ACTIVE" + "state":"ACTIVE", + "restartedProcessInstanceId":"2bef365d-3406-11ef-bd73-0a0027000003" } }'] /> diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/job/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/job/get.ftl index 9cb9597513a..bebe599a910 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/job/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/job/get.ftl @@ -49,7 +49,8 @@ "suspended": false, "priority": 10, "tenantId": null, - "createTime": "2018-05-05T17:00:00+0200" + "createTime": "2018-05-05T17:00:00+0200", + "batchId": "aBatchId" }, { "id": "anotherJobId", @@ -65,7 +66,8 @@ "suspended": true, "priority": 8, "tenantId": null, - "createTime": "2018-05-05T17:00:00+0200" + "createTime": "2018-05-05T17:00:00+0200", + "batchId": null } ] }'] diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/job/post.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/job/post.ftl index d612bf17b6f..71846fd10a7 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/job/post.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/job/post.ftl @@ -82,7 +82,8 @@ "suspended": false, "priority": 10, "tenantId": null, - "createTime": "2018-05-05T17:00:00+0200" + "createTime": "2018-05-05T17:00:00+0200", + "batchId": "aBatchId" }, { "id": "anotherJobId", @@ -98,7 +99,8 @@ "suspended": true, "priority": 8, "tenantId": null, - "createTime": "2018-05-05T17:00:00+0200" + "createTime": "2018-05-05T17:00:00+0200", + "batchId": null } ] }'] diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/job/{id}/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/job/{id}/get.ftl index 51327ed2413..2b94543fa2a 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/job/{id}/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/job/{id}/get.ftl @@ -43,7 +43,8 @@ "suspended": false, "priority": 10, "tenantId": null, - "createTime": "2018-05-05T17:00:00+0200" + "createTime": "2018-05-05T17:00:00+0200", + "batchId": "aBatchId" } }'] /> diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/metrics/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/metrics/get.ftl index 064b12ee410..7540c5c8e4f 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/metrics/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/metrics/get.ftl @@ -59,7 +59,8 @@ <@lib.parameter name = "interval" location = "query" - type = "string" + type = "integer" + format = "int64" defaultValue = "900" desc = "The interval for which the metrics should be aggregated. Time unit is seconds. Default: The interval is set to 15 minutes (900 seconds)." /> diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/task/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/task/get.ftl index bfd8941a0cf..d52fcbb8195 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/task/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/task/get.ftl @@ -34,11 +34,11 @@ <@lib.response code = "200" - dto = "TaskDto" + dto = "TaskWithAttachmentAndCommentDto" array = true desc = "Request successful." examples = ['"example-1": { - "summary": "Status 200 response", + "summary": "Status 200 response 1", "description": "Response for GET `/task?assignee=anAssignee&delegationState=RESOLVED&maxPriority=50`", "value": [ { @@ -72,6 +72,43 @@ "taskState": "aTaskState" } ] + }', + '"example-2": { + "summary": "Status 200 response 2", + "description": "Response for GET `/task?assignee=anAssignee&withCommentAttachmentInfo=true`", + "value": [ + { + "id":"anId", + "name":"aName", + "assignee":"anAssignee", + "created":"2013-01-23T13:42:42.657+0200", + "due":"2013-01-23T13:49:42.323+0200", + "followUp:":"2013-01-23T13:44:42.987+0200", + "lastUpdated:":"2013-01-23T13:44:42.987+0200", + "delegationState":"RESOLVED", + "description":"aDescription", + "executionId":"anExecution", + "owner":"anOwner", + "parentTaskId":"aParentId", + "priority":42, + "processDefinitionId":"aProcDefId", + "processInstanceId":"aProcInstId", + "caseDefinitionId":"aCaseDefId", + "caseInstanceId":"aCaseInstId", + "caseExecutionId":"aCaseExecution", + "taskDefinitionKey":"aTaskDefinitionKey", + "suspended": false, + "formKey":"aFormKey", + "operatonFormRef":{ + "key": "aOperatonFormKey", + "binding": "version", + "version": 2 + }, + "tenantId": "aTenantId", + "attachment":false, + "comment":false + } + ] }'] /> <@lib.response diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/task/post.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/task/post.ftl index f6ef45141db..70785997c0d 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/task/post.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/task/post.ftl @@ -68,6 +68,7 @@ "description": "Logical query: assignee = \\"John Munda\\" AND (name = \\"Approve Invoice\\" OR priority = 5) AND (suspended = false OR taskDefinitionKey = \\"approveInvoice\\")", "value": { "assignee": "John Munda", + "withCommentAttachmentInfo": "true", "orQueries": [ { "name": "Approve Invoice", @@ -86,7 +87,7 @@ <@lib.response code = "200" - dto = "TaskDto" + dto = "TaskWithAttachmentAndCommentDto" array = true desc = "Request successful." examples = ['"example-1": { @@ -150,7 +151,9 @@ "suspended": false, "formKey": "embedded:app:develop/invoice-forms/approve-invoice.html", "tenantId": null, - "taskState": "aTaskState" + "taskState": "aTaskState", + "attachment":false, + "comment":false } ] }' diff --git a/engine-rest/engine-rest-openapi/src/main/templates/paths/task/{id}/get.ftl b/engine-rest/engine-rest-openapi/src/main/templates/paths/task/{id}/get.ftl index f7298125e60..847cca6566b 100644 --- a/engine-rest/engine-rest-openapi/src/main/templates/paths/task/{id}/get.ftl +++ b/engine-rest/engine-rest-openapi/src/main/templates/paths/task/{id}/get.ftl @@ -23,7 +23,7 @@ <@lib.response code = "200" - dto = "TaskDto" + dto = "TaskWithAttachmentAndCommentDto" desc = "Request successful." examples = ['"example-1": { "summary": "GET /task/anId Response", @@ -56,6 +56,38 @@ "tenantId":"aTenantId", "taskState": "aTaskState" } + }', + '"example-2": { + "summary": "GET /task/anId?withCommentAttachmentInfo=true Response", + "value": [ + { + "id": "349fffa8-6571-11e7-9a44-d6940f5ef88d", + "name": "Approve Invoice", + "assignee": "John Munda", + "created": "2017-07-10T15:10:54.670+0200", + "due": "2017-07-17T15:10:54.670+0200", + "followUp": null, + "lastUpdated": "2017-07-17T15:10:54.670+0200", + "delegationState": null, + "description": "Approve the invoice (or not).", + "executionId": "349f8a5c-6571-11e7-9a44-d6940f5ef88d", + "owner": null, + "parentTaskId": null, + "priority": 50, + "processDefinitionId": "invoice:1:2c8d8057-6571-11e7-9a44-d6940f5ef88d", + "processInstanceId": "349f8a5c-6571-11e7-9a44-d6940f5ef88d", + "taskDefinitionKey": "approveInvoice", + "caseExecutionId": null, + "caseInstanceId": null, + "caseDefinitionId": null, + "suspended": false, + "formKey": "embedded:app:develop/invoice-forms/approve-invoice.html", + "tenantId": null, + "taskState": "aTaskState", + "attachment":false, + "comment":false + } + ] }'] /> <@lib.response diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/TaskRestService.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/TaskRestService.java index 9638e9061d6..facd75ff18c 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/TaskRestService.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/TaskRestService.java @@ -36,7 +36,7 @@ public interface TaskRestService { public static final String PATH = "/task"; @Path("/{id}") - TaskResource getTask(@PathParam("id") String id); + TaskResource getTask(@PathParam("id") String id, @QueryParam("withCommentAttachmentInfo") boolean withCommentAttachmentInfo); @GET @Produces({MediaType.APPLICATION_JSON, Hal.APPLICATION_HAL_JSON}) diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/ModificationDto.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/ModificationDto.java index aa41d69bfde..c5ad56679d5 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/ModificationDto.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/ModificationDto.java @@ -19,6 +19,8 @@ import java.util.List; import org.operaton.bpm.engine.ProcessEngine; +import org.operaton.bpm.engine.history.HistoricProcessInstanceQuery; +import org.operaton.bpm.engine.rest.dto.history.HistoricProcessInstanceQueryDto; import org.operaton.bpm.engine.rest.dto.runtime.ProcessInstanceQueryDto; import org.operaton.bpm.engine.rest.dto.runtime.modification.ProcessInstanceModificationInstructionDto; import org.operaton.bpm.engine.runtime.ModificationBuilder; @@ -30,6 +32,7 @@ public class ModificationDto { protected List instructions; protected List processInstanceIds; protected ProcessInstanceQueryDto processInstanceQuery; + protected HistoricProcessInstanceQueryDto historicProcessInstanceQuery; protected String processDefinitionId; protected boolean skipIoMappings; protected boolean skipCustomListeners; @@ -99,4 +102,11 @@ public void setAnnotation(String annotation) { this.annotation = annotation; } + public HistoricProcessInstanceQueryDto getHistoricProcessInstanceQuery() { + return historicProcessInstanceQuery; + } + + public void setHistoricProcessInstanceQuery(HistoricProcessInstanceQueryDto historicProcessInstanceQuery) { + this.historicProcessInstanceQuery = historicProcessInstanceQuery; + } } diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricJobLogDto.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricJobLogDto.java index 6e84b3aa8e2..efffcb8c932 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricJobLogDto.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricJobLogDto.java @@ -50,6 +50,7 @@ public class HistoricJobLogDto { protected String tenantId; protected String hostname; protected String rootProcessInstanceId; + protected String batchId; protected boolean creationLog; protected boolean failureLog; @@ -140,6 +141,10 @@ public String getRootProcessInstanceId() { return rootProcessInstanceId; } + public String getBatchId() { + return batchId; + } + public boolean isCreationLog() { return creationLog; } @@ -183,6 +188,7 @@ public static HistoricJobLogDto fromHistoricJobLog(HistoricJobLog historicJobLog result.tenantId = historicJobLog.getTenantId(); result.hostname = historicJobLog.getHostname(); result.rootProcessInstanceId = historicJobLog.getRootProcessInstanceId(); + result.batchId = historicJobLog.getBatchId(); result.creationLog = historicJobLog.isCreationLog(); result.failureLog = historicJobLog.isFailureLog(); diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceDto.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceDto.java index fbc470d2a3a..cfdb502a9d2 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceDto.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceDto.java @@ -40,6 +40,7 @@ public class HistoricProcessInstanceDto { private String caseInstanceId; private String tenantId; private String state; + private String restartedProcessInstanceId; public String getId() { return id; @@ -129,6 +130,15 @@ public void setRootProcessInstanceId(String rootProcessInstanceId) { this.rootProcessInstanceId = rootProcessInstanceId; } + public String getRestartedProcessInstanceId() { + return restartedProcessInstanceId; + } + + public void setRestartedProcessInstanceId(String restartedProcessInstanceId) { + this.restartedProcessInstanceId = restartedProcessInstanceId; + } + + public static HistoricProcessInstanceDto fromHistoricProcessInstance(HistoricProcessInstance historicProcessInstance) { HistoricProcessInstanceDto dto = new HistoricProcessInstanceDto(); @@ -152,6 +162,7 @@ public static HistoricProcessInstanceDto fromHistoricProcessInstance(HistoricPro dto.caseInstanceId = historicProcessInstance.getCaseInstanceId(); dto.tenantId = historicProcessInstance.getTenantId(); dto.state = historicProcessInstance.getState(); + dto.restartedProcessInstanceId = historicProcessInstance.getRestartedProcessInstanceId(); return dto; } diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceQueryDto.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceQueryDto.java index a121c67dacb..c607f8625ee 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceQueryDto.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/history/HistoricProcessInstanceQueryDto.java @@ -109,11 +109,13 @@ public class HistoricProcessInstanceQueryDto extends AbstractQueryDto executedActivityIdIn; private List activeActivityIdIn; + private List activityIdIn; private Boolean active; private Boolean suspended; private Boolean completed; private Boolean externallyTerminated; private Boolean internallyTerminated; + private List incidentIds; private List variables; @@ -306,6 +308,11 @@ public void setIncidentType(String incidentType) { this.incidentType = incidentType; } + @OperatonQueryParam(value = "incidentIdIn", converter = StringListConverter.class) + public void setIncidentIdIn(List incidentIds) { + this.incidentIds = incidentIds; + } + @OperatonQueryParam(value = "tenantIdIn", converter = StringListConverter.class) public void setTenantIdIn(List tenantIds) { this.tenantIds = tenantIds; @@ -336,6 +343,11 @@ public void setActiveActivityIdIn(List activeActivityIdIn) { this.activeActivityIdIn = activeActivityIdIn; } + @OperatonQueryParam(value = "activityIdIn", converter = StringListConverter.class) + public void setActivityIdIn(List activityIdIn) { + this.activityIdIn = activityIdIn; + } + @OperatonQueryParam(value = "executedJobAfter", converter = DateConverter.class) public void setExecutedJobAfter(Date executedJobAfter) { this.executedJobAfter = executedJobAfter; @@ -443,6 +455,9 @@ protected void applyFilters(HistoricProcessInstanceQuery query) { if (withRootIncidents != null && withRootIncidents) { query.withRootIncidents(); } + if (incidentIds != null && !incidentIds.isEmpty()) { + query.incidentIdIn(incidentIds.toArray(new String[0])); + } if (incidentStatus != null) { query.incidentStatus(incidentStatus); } @@ -539,6 +554,10 @@ protected void applyFilters(HistoricProcessInstanceQuery query) { query.activeActivityIdIn(activeActivityIdIn.toArray(new String[0])); } + if(activityIdIn!= null && !activityIdIn.isEmpty()) { + query.activityIdIn(activityIdIn.toArray(new String[0])); + } + if (executedJobAfter != null) { query.executedJobAfter(executedJobAfter); } diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/runtime/JobDto.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/runtime/JobDto.java index 14ff09e3b1d..0a1c451c9c9 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/runtime/JobDto.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/runtime/JobDto.java @@ -36,6 +36,7 @@ public class JobDto { protected long priority; protected String tenantId; protected Date createTime; + protected String batchId; public static JobDto fromJob(Job job) { JobDto dto = new JobDto(); @@ -53,6 +54,7 @@ public static JobDto fromJob(Job job) { dto.priority = job.getPriority(); dto.tenantId = job.getTenantId(); dto.createTime = job.getCreateTime(); + dto.batchId = job.getBatchId(); return dto; } @@ -113,4 +115,8 @@ public Date getCreateTime() { return createTime; } + public String getBatchId() { + return batchId; + } + } diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskDto.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskDto.java index 64643dcc4f9..e30284c44be 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskDto.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskDto.java @@ -21,6 +21,7 @@ import org.operaton.bpm.engine.BadUserRequestException; import org.operaton.bpm.engine.form.OperatonFormRef; import org.operaton.bpm.engine.rest.dto.converter.DelegationStateConverter; +import org.operaton.bpm.engine.runtime.ProcessInstance; import org.operaton.bpm.engine.task.DelegationState; import org.operaton.bpm.engine.task.Task; @@ -54,6 +55,44 @@ public class TaskDto { */ private String taskState; + public TaskDto() { + } + + public TaskDto(Task task) { + this.id = task.getId(); + this.name = task.getName(); + this.assignee = task.getAssignee(); + this.created = task.getCreateTime(); + this.lastUpdated = task.getLastUpdated(); + this.due = task.getDueDate(); + this.followUp = task.getFollowUpDate(); + + if (task.getDelegationState() != null) { + this.delegationState = task.getDelegationState().toString(); + } + + this.description = task.getDescription(); + this.executionId = task.getExecutionId(); + this.owner = task.getOwner(); + this.parentTaskId = task.getParentTaskId(); + this.priority = task.getPriority(); + this.processDefinitionId = task.getProcessDefinitionId(); + this.processInstanceId = task.getProcessInstanceId(); + this.taskDefinitionKey = task.getTaskDefinitionKey(); + this.caseDefinitionId = task.getCaseDefinitionId(); + this.caseExecutionId = task.getCaseExecutionId(); + this.caseInstanceId = task.getCaseInstanceId(); + this.suspended = task.isSuspended(); + this.tenantId = task.getTenantId(); + this.taskState = task.getTaskState(); + try { + this.formKey = task.getFormKey(); + this.operatonFormRef = task.getOperatonFormRef(); + } + catch (BadUserRequestException e) { + // ignore (initializeFormKeys was not called) + } + } public String getId() { return id; } diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskQueryDto.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskQueryDto.java index 797eba1ec42..554438fea0c 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskQueryDto.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskQueryDto.java @@ -131,6 +131,7 @@ public class TaskQueryDto extends AbstractQueryDto { private String[] assigneeNotIn; private String candidateGroup; private String candidateGroupExpression; + private String candidateGroupLike; private String candidateUser; private String candidateUserExpression; private Boolean includeAssignedTasks; @@ -212,6 +213,8 @@ public class TaskQueryDto extends AbstractQueryDto { private List orQueries; + private Boolean withCommentAttachmentInfo; + public TaskQueryDto() { } @@ -345,6 +348,11 @@ public void setCandidateGroupExpression(String candidateGroupExpression) { this.candidateGroupExpression = candidateGroupExpression; } + @OperatonQueryParam("candidateGroupLike") + public void setCandidateGroupLike(String candidateGroupLike) { + this.candidateGroupLike = candidateGroupLike; + } + @OperatonQueryParam(value = "withCandidateGroups", converter = BooleanConverter.class) public void setWithCandidateGroups(Boolean withCandidateGroups) { this.withCandidateGroups = withCandidateGroups; @@ -708,6 +716,11 @@ public void setVariableValuesIgnoreCase(Boolean variableValuesCaseInsensitive) { this.variableValuesIgnoreCase = variableValuesCaseInsensitive; } + @OperatonQueryParam(value = "withCommentAttachmentInfo", converter = BooleanConverter.class) + public void setWithCommentAttachmentInfo(Boolean withCommentAttachmentInfo) { + this.withCommentAttachmentInfo = withCommentAttachmentInfo; + } + @Override protected boolean isValidSortByValue(String value) { return VALID_SORT_BY_VALUES.contains(value); @@ -814,6 +827,10 @@ public String getCandidateGroupExpression() { return candidateGroupExpression; } + public String getCandidateGroupLike() { + return candidateGroupLike; + } + public String getCandidateUser() { return candidateUser; } @@ -1078,6 +1095,8 @@ public Boolean isVariableValuesIgnoreCase() { return variableValuesIgnoreCase; } + public Boolean getWithCommentAttachmentInfo() { return withCommentAttachmentInfo;} + @Override protected void applyFilters(TaskQuery query) { if (orQueries != null) { @@ -1160,6 +1179,9 @@ protected void applyFilters(TaskQuery query) { if (candidateGroupExpression != null) { query.taskCandidateGroupExpression(candidateGroupExpression); } + if (candidateGroupLike != null) { + query.taskCandidateGroupLike(candidateGroupLike); + } if (withCandidateGroups != null && withCandidateGroups) { query.withCandidateGroups(); } @@ -1442,6 +1464,9 @@ protected void applyFilters(TaskQuery query) { } } } + if (withCommentAttachmentInfo != null && withCommentAttachmentInfo) { + query.withCommentAttachmentInfo(); + } } @Override @@ -1558,6 +1583,7 @@ public static TaskQueryDto fromQuery(Query query, boolean isOrQueryActive) dto.candidateUser = taskQuery.getCandidateUser(); dto.candidateGroup = taskQuery.getCandidateGroup(); + dto.candidateGroupLike = taskQuery.getCandidateGroupLike(); dto.candidateGroups = taskQuery.getCandidateGroupsInternal(); dto.includeAssignedTasks = taskQuery.isIncludeAssignedTasksInternal(); dto.withCandidateGroups = taskQuery.isWithCandidateGroups(); diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskWithAttachmentAndCommentDto.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskWithAttachmentAndCommentDto.java new file mode 100644 index 00000000000..c37a6c432ef --- /dev/null +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/dto/task/TaskWithAttachmentAndCommentDto.java @@ -0,0 +1,54 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.operaton.bpm.engine.rest.dto.task; + +import org.operaton.bpm.engine.task.Task; + +public class TaskWithAttachmentAndCommentDto extends TaskDto { + + private boolean hasAttachment; + private boolean hasComment; + + public TaskWithAttachmentAndCommentDto() { + } + + public TaskWithAttachmentAndCommentDto(Task task) { + super(task); + } + public boolean getAttachment() { + return hasAttachment; + } + public void setAttachment(boolean hasAttachment) { + this.hasAttachment = hasAttachment; + } + + public boolean getComment() { + return hasComment; + } + + public void setComment(boolean hasComment) { + this.hasComment = hasComment; + } + + public static TaskDto fromEntity(Task task) { + TaskWithAttachmentAndCommentDto result = new TaskWithAttachmentAndCommentDto(task); + + result.hasAttachment = task.hasAttachment(); + result.hasComment = task.hasComment(); + return result; + } +} diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/impl/ModificationRestServiceImpl.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/impl/ModificationRestServiceImpl.java index 04ddf71bbc3..9f1188d0b3a 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/impl/ModificationRestServiceImpl.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/impl/ModificationRestServiceImpl.java @@ -22,9 +22,11 @@ import org.operaton.bpm.engine.BadUserRequestException; import org.operaton.bpm.engine.batch.Batch; +import org.operaton.bpm.engine.history.HistoricProcessInstanceQuery; import org.operaton.bpm.engine.rest.ModificationRestService; import org.operaton.bpm.engine.rest.dto.ModificationDto; import org.operaton.bpm.engine.rest.dto.batch.BatchDto; +import org.operaton.bpm.engine.rest.dto.history.HistoricProcessInstanceQueryDto; import org.operaton.bpm.engine.rest.dto.runtime.ProcessInstanceQueryDto; import org.operaton.bpm.engine.rest.exception.InvalidRequestException; import org.operaton.bpm.engine.runtime.ModificationBuilder; @@ -74,6 +76,12 @@ private ModificationBuilder createModificationBuilder(ModificationDto dto) { builder.processInstanceQuery(processInstanceQuery); } + HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = dto.getHistoricProcessInstanceQuery(); + if(historicProcessInstanceQueryDto != null) { + HistoricProcessInstanceQuery historicProcessInstanceQuery = historicProcessInstanceQueryDto.toQuery(getProcessEngine()); + builder.historicProcessInstanceQuery(historicProcessInstanceQuery); + } + if (dto.isSkipCustomListeners()) { builder.skipCustomListeners(); } diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/impl/TaskRestServiceImpl.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/impl/TaskRestServiceImpl.java index 73225023602..cfd6ab8d4e2 100644 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/impl/TaskRestServiceImpl.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/impl/TaskRestServiceImpl.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; @@ -32,6 +33,7 @@ import org.operaton.bpm.engine.rest.dto.CountResultDto; import org.operaton.bpm.engine.rest.dto.task.TaskDto; import org.operaton.bpm.engine.rest.dto.task.TaskQueryDto; +import org.operaton.bpm.engine.rest.dto.task.TaskWithAttachmentAndCommentDto; import org.operaton.bpm.engine.rest.exception.InvalidRequestException; import org.operaton.bpm.engine.rest.hal.Hal; import org.operaton.bpm.engine.rest.hal.task.HalTaskList; @@ -66,6 +68,7 @@ else if (Hal.APPLICATION_HAL_JSON_TYPE.equals(variant.getMediaType())) { } public List getJsonTasks(UriInfo uriInfo, Integer firstResult, Integer maxResults) { + // get list of tasks TaskQueryDto queryDto = new TaskQueryDto(getObjectMapper(), uriInfo.getQueryParameters()); return queryTasks(queryDto, firstResult, maxResults); } @@ -95,11 +98,12 @@ public List queryTasks(TaskQueryDto queryDto, Integer firstResult, List matchingTasks = executeTaskQuery(firstResult, maxResults, query); List tasks = new ArrayList(); - for (Task task : matchingTasks) { - TaskDto returnTask = TaskDto.fromEntity(task); - tasks.add(returnTask); + if (Boolean.TRUE.equals(queryDto.getWithCommentAttachmentInfo())) { + tasks = matchingTasks.stream().map(TaskWithAttachmentAndCommentDto::fromEntity).collect(Collectors.toList()); + } + else { + tasks = matchingTasks.stream().map(TaskDto::fromEntity).collect(Collectors.toList()); } - return tasks; } @@ -130,8 +134,8 @@ public CountResultDto queryTasksCount(TaskQueryDto queryDto) { } @Override - public TaskResource getTask(String id) { - return new TaskResourceImpl(getProcessEngine(), id, relativeRootResourcePath, getObjectMapper()); + public TaskResource getTask(String id, boolean withCommentAttachmentInfo) { + return new TaskResourceImpl(getProcessEngine(), id, relativeRootResourcePath, getObjectMapper(), withCommentAttachmentInfo); } @Override diff --git a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/sub/task/impl/TaskResourceImpl.java b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/sub/task/impl/TaskResourceImpl.java index a4ea338a33e..4bec9af4f24 100755 --- a/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/sub/task/impl/TaskResourceImpl.java +++ b/engine-rest/engine-rest/src/main/java/org/operaton/bpm/engine/rest/sub/task/impl/TaskResourceImpl.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Supplier; import javax.ws.rs.core.MediaType; @@ -46,13 +47,7 @@ import org.operaton.bpm.engine.impl.identity.Authentication; import org.operaton.bpm.engine.rest.dto.VariableValueDto; import org.operaton.bpm.engine.rest.dto.converter.StringListConverter; -import org.operaton.bpm.engine.rest.dto.task.CompleteTaskDto; -import org.operaton.bpm.engine.rest.dto.task.FormDto; -import org.operaton.bpm.engine.rest.dto.task.IdentityLinkDto; -import org.operaton.bpm.engine.rest.dto.task.TaskBpmnErrorDto; -import org.operaton.bpm.engine.rest.dto.task.TaskDto; -import org.operaton.bpm.engine.rest.dto.task.TaskEscalationDto; -import org.operaton.bpm.engine.rest.dto.task.UserIdDto; +import org.operaton.bpm.engine.rest.dto.task.*; import org.operaton.bpm.engine.rest.exception.InvalidRequestException; import org.operaton.bpm.engine.rest.exception.RestException; import org.operaton.bpm.engine.rest.hal.Hal; @@ -78,12 +73,14 @@ public class TaskResourceImpl implements TaskResource { protected String taskId; protected String rootResourcePath; protected ObjectMapper objectMapper; + protected boolean withCommentAttachmentInfo; - public TaskResourceImpl(ProcessEngine engine, String taskId, String rootResourcePath, ObjectMapper objectMapper) { + public TaskResourceImpl(ProcessEngine engine, String taskId, String rootResourcePath, ObjectMapper objectMapper, boolean withCommentAttachmentInfo) { this.engine = engine; this.taskId = taskId; this.rootResourcePath = rootResourcePath; this.objectMapper = objectMapper; + this.withCommentAttachmentInfo = withCommentAttachmentInfo; } @Override @@ -192,16 +189,20 @@ else if (Hal.APPLICATION_HAL_JSON_TYPE.equals(variant.getMediaType())) { } public TaskDto getJsonTask() { - Task task = getTaskById(taskId); + Task task = getTaskById(taskId, withCommentAttachmentInfo); if (task == null) { throw new InvalidRequestException(Status.NOT_FOUND, "No matching task with id " + taskId); } - - return TaskDto.fromEntity(task); + if (withCommentAttachmentInfo) { + return TaskWithAttachmentAndCommentDto.fromEntity(task); + } + else { + return TaskDto.fromEntity(task); + } } public HalTask getHalTask() { - Task task = getTaskById(taskId); + Task task = getTaskById(taskId, withCommentAttachmentInfo); if (task == null) { throw new InvalidRequestException(Status.NOT_FOUND, "No matching task with id " + taskId); } @@ -212,7 +213,7 @@ public HalTask getHalTask() { @Override public FormDto getForm() { FormService formService = engine.getFormService(); - Task task = getTaskById(taskId); + Task task = getTaskById(taskId, withCommentAttachmentInfo); FormData formData; try { formData = formService.getTaskFormData(taskId); @@ -368,7 +369,7 @@ public Map getFormVariables(String variableNames, bool public void updateTask(TaskDto taskDto) { TaskService taskService = engine.getTaskService(); - Task task = getTaskById(taskId); + Task task = getTaskById(taskId, withCommentAttachmentInfo); if (task == null) { throw new InvalidRequestException(Status.NOT_FOUND, "No matching task with id " + taskId); @@ -433,8 +434,13 @@ public void handleEscalation(TaskEscalationDto dto) { } } - protected Task getTaskById(String id) { - return engine.getTaskService().createTaskQuery().taskId(id).initializeFormKeys().singleResult(); + protected Task getTaskById(String id, boolean withCommentAttachmentInfo) { + if (withCommentAttachmentInfo) { + return engine.getTaskService().createTaskQuery().taskId(id).withCommentAttachmentInfo().initializeFormKeys().singleResult(); + } + else{ + return engine.getTaskService().createTaskQuery().taskId(id).initializeFormKeys().singleResult(); + } } protected String getTaskFormMediaType(String taskId) { diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/JobRestServiceInteractionTest.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/JobRestServiceInteractionTest.java index 197d8a67b4b..5356d023e27 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/JobRestServiceInteractionTest.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/JobRestServiceInteractionTest.java @@ -117,6 +117,7 @@ public void setUpRuntimeData() { .jobDefinitionId(MockProvider.EXAMPLE_JOB_DEFINITION_ID) .tenantId(MockProvider.EXAMPLE_TENANT_ID) .createTime(DateTimeUtil.parseDate(MockProvider.EXAMPLE_JOB_CREATE_TIME)) + .batchId(MockProvider.EXAMPLE_BATCH_ID) .build(); when(mockQuery.singleResult()).thenReturn(mockedJob); @@ -294,6 +295,7 @@ public void testSimpleJobGet() { .body("jobDefinitionId", equalTo(MockProvider.EXAMPLE_JOB_DEFINITION_ID)) .body("tenantId", equalTo(MockProvider.EXAMPLE_TENANT_ID)) .body("createTime", equalTo(MockProvider.EXAMPLE_JOB_CREATE_TIME)) + .body("batchId", equalTo(MockProvider.EXAMPLE_BATCH_ID)) .when() .get(SINGLE_JOB_RESOURCE_URL); diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/JobRestServiceQueryTest.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/JobRestServiceQueryTest.java index c3d2ab9be4b..70aad2071f6 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/JobRestServiceQueryTest.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/JobRestServiceQueryTest.java @@ -164,6 +164,7 @@ public void testSimpleJobQuery() { String returnedJobDefinitionId= from(content).getString("[0].jobDefinitionId"); String returnedTenantId = from(content).getString("[0].tenantId"); String returnedCreateTime = from(content).getString("[0].createTime"); + String returnedBatchId = from(content).getString("[0].batchId"); Assert.assertEquals(MockProvider.EXAMPLE_JOB_ID, returnedJobId); Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID, returnedProcessInstanceId); @@ -179,6 +180,7 @@ public void testSimpleJobQuery() { Assert.assertEquals(MockProvider.EXAMPLE_JOB_DEFINITION_ID, returnedJobDefinitionId); Assert.assertEquals(MockProvider.EXAMPLE_TENANT_ID, returnedTenantId); Assert.assertEquals(MockProvider.EXAMPLE_JOB_CREATE_TIME, returnedCreateTime); + Assert.assertEquals(MockProvider.EXAMPLE_BATCH_ID, returnedBatchId); } private interface DateParameters { diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/ModificationRestServiceInteractionTest.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/ModificationRestServiceInteractionTest.java index ec5dc387a94..2399c790475 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/ModificationRestServiceInteractionTest.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/ModificationRestServiceInteractionTest.java @@ -32,9 +32,12 @@ import org.operaton.bpm.engine.AuthorizationException; import org.operaton.bpm.engine.BadUserRequestException; +import org.operaton.bpm.engine.HistoryService; import org.operaton.bpm.engine.RuntimeService; import org.operaton.bpm.engine.batch.Batch; +import org.operaton.bpm.engine.impl.HistoricProcessInstanceQueryImpl; import org.operaton.bpm.engine.impl.ProcessInstanceQueryImpl; +import org.operaton.bpm.engine.rest.dto.history.HistoricProcessInstanceQueryDto; import org.operaton.bpm.engine.rest.dto.runtime.ProcessInstanceQueryDto; import org.operaton.bpm.engine.rest.exception.InvalidRequestException; import org.operaton.bpm.engine.rest.util.ModificationInstructionBuilder; @@ -57,6 +60,7 @@ public class ModificationRestServiceInteractionTest extends AbstractRestServiceT protected static final String EXECUTE_MODIFICATION_ASYNC_URL = PROCESS_INSTANCE_URL + "/executeAsync"; protected RuntimeService runtimeServiceMock; + protected HistoryService historyServiceMock; protected ModificationBuilder modificationBuilderMock; @Before @@ -64,6 +68,9 @@ public void setUpRuntimeData() { runtimeServiceMock = mock(RuntimeService.class); when(processEngine.getRuntimeService()).thenReturn(runtimeServiceMock); + historyServiceMock = mock(HistoryService.class); + when(processEngine.getHistoryService()).thenReturn(historyServiceMock); + modificationBuilderMock = mock(ModificationBuilder.class); when(modificationBuilderMock.cancelAllForActivity(any())).thenReturn(modificationBuilderMock); when(modificationBuilderMock.startAfterActivity(any())).thenReturn(modificationBuilderMock); @@ -299,6 +306,39 @@ public void executeModificationWithValidProcessInstanceQuerySync() { verify(modificationBuilderMock).execute(); } + @Test + public void executeModificationWithValidHistoricProcessInstanceQuerySync() { + + when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl()); + Map json = new HashMap(); + + List> instructions = new ArrayList>(); + instructions.add(ModificationInstructionBuilder.startAfter().activityId("activityId").getJson()); + json.put("processDefinitionId", "processDefinitionId"); + + HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto(); + historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo"); + + json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto); + + json.put("instructions", instructions); + + given() + .contentType(ContentType.JSON) + .body(json) + .then() + .expect() + .statusCode(Status.NO_CONTENT.getStatusCode()) + .when() + .post(EXECUTE_MODIFICATION_SYNC_URL); + + verify(historyServiceMock, times(1)).createHistoricProcessInstanceQuery(); + verify(modificationBuilderMock).startAfterActivity("activityId"); + verify(modificationBuilderMock).historicProcessInstanceQuery(historicProcessInstanceQueryDto.toQuery(processEngine)); + verify(modificationBuilderMock).execute(); + } + + @Test public void executeModificationWithValidProcessInstanceQueryAsync() { @@ -330,6 +370,74 @@ public void executeModificationWithValidProcessInstanceQueryAsync() { verify(modificationBuilderMock).executeAsync(); } + @Test + public void executeModificationWithValidHistoricProcessInstanceQueryAsync() { + when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl()); + Map json = new HashMap(); + + List> instructions = new ArrayList>(); + instructions.add(ModificationInstructionBuilder.startAfter().activityId("activityId").getJson()); + + HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto(); + historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo"); + + json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto); + json.put("instructions", instructions); + json.put("processDefinitionId", "processDefinitionId"); + + given() + .contentType(ContentType.JSON) + .body(json) + .then() + .expect() + .statusCode(Status.OK.getStatusCode()) + .when() + .post(EXECUTE_MODIFICATION_ASYNC_URL); + + verify(historyServiceMock, times(1)).createHistoricProcessInstanceQuery(); + verify(modificationBuilderMock).startAfterActivity("activityId"); + verify(modificationBuilderMock).historicProcessInstanceQuery(historicProcessInstanceQueryDto.toQuery(processEngine)); + verify(modificationBuilderMock).executeAsync(); + } + + @Test + public void executeModificationWithBothProcessInstanceQueries() { + when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl()); + when(runtimeServiceMock.createProcessInstanceQuery()).thenReturn(new ProcessInstanceQueryImpl()); + + Map json = new HashMap(); + + List> instructions = new ArrayList>(); + instructions.add(ModificationInstructionBuilder.startAfter().activityId("activityId").getJson()); + + HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto(); + historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo"); + + ProcessInstanceQueryDto processInstanceQueryDto = new ProcessInstanceQueryDto(); + processInstanceQueryDto.setBusinessKey("foo"); + + json.put("processInstanceQuery", processInstanceQueryDto); + json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto); + json.put("instructions", instructions); + json.put("processDefinitionId", "processDefinitionId"); + + given() + .contentType(ContentType.JSON) + .body(json) + .then() + .expect() + .statusCode(Status.OK.getStatusCode()) + .when() + .post(EXECUTE_MODIFICATION_ASYNC_URL); + + verify(historyServiceMock, times(1)).createHistoricProcessInstanceQuery(); + verify(modificationBuilderMock).startAfterActivity("activityId"); + verify(modificationBuilderMock).historicProcessInstanceQuery(historicProcessInstanceQueryDto.toQuery(processEngine)); + verify(runtimeServiceMock, times(1)).createProcessInstanceQuery(); + verify(modificationBuilderMock).processInstanceQuery(processInstanceQueryDto.toQuery(processEngine)); + verify(modificationBuilderMock).executeAsync(); + } + @Test public void executeModificationWithInvalidProcessInstanceQuerySync() { @@ -359,6 +467,35 @@ public void executeModificationWithInvalidProcessInstanceQuerySync() { } + @Test + public void executeModificationWithInvalidHistoricProcessInstanceQuerySync() { + when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl()); + + Map json = new HashMap(); + + String message = "Process instance ids is null"; + doThrow(new BadUserRequestException(message)).when(modificationBuilderMock).execute(); + + List> instructions = new ArrayList>(); + instructions.add(ModificationInstructionBuilder.startAfter().activityId("acivityId").getJson()); + + HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto(); + historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo"); + + json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto); + json.put("instructions", instructions); + json.put("processDefinitionId", "processDefinitionId"); + + given() + .contentType(ContentType.JSON) + .body(json) + .then() + .expect() + .statusCode(Status.BAD_REQUEST.getStatusCode()) + .when() + .post(EXECUTE_MODIFICATION_SYNC_URL); + } + @Test public void executeModificationWithInvalidProcessInstanceQueryAsync() { @@ -384,6 +521,31 @@ public void executeModificationWithInvalidProcessInstanceQueryAsync() { .post(EXECUTE_MODIFICATION_ASYNC_URL); } + @Test + public void executeModificationWithInvalidHistoricProcessInstanceQueryAsync() { + when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl()); + Map json = new HashMap(); + + List> instructions = new ArrayList>(); + instructions.add(ModificationInstructionBuilder.startAfter().activityId("acivityId").getJson()); + + HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto(); + historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo"); + + json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto); + json.put("instructions", instructions); + json.put("processDefinitionId", "processDefinitionId"); + + given() + .contentType(ContentType.JSON) + .body(json) + .then() + .expect() + .statusCode(Status.OK.getStatusCode()) + .when() + .post(EXECUTE_MODIFICATION_ASYNC_URL); + } + @Test public void executeModificationWithNullInstructionsSync() { doThrow(new BadUserRequestException("Instructions must be set")).when(modificationBuilderMock).execute(); diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/TaskRestServiceInteractionTest.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/TaskRestServiceInteractionTest.java index cadfbae2be2..2c45ffa4616 100755 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/TaskRestServiceInteractionTest.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/TaskRestServiceInteractionTest.java @@ -146,6 +146,8 @@ import io.restassured.http.ContentType; import io.restassured.path.json.JsonPath; import io.restassured.response.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class TaskRestServiceInteractionTest extends AbstractRestServiceTest { @@ -214,6 +216,7 @@ public void setUpRuntimeData() { mockQuery = mock(TaskQuery.class); when(mockQuery.initializeFormKeys()).thenReturn(mockQuery); when(mockQuery.taskId(any())).thenReturn(mockQuery); + when(mockQuery.withCommentAttachmentInfo()).thenReturn(mockQuery); when(mockQuery.singleResult()).thenReturn(mockTask); when(taskServiceMock.createTaskQuery()).thenReturn(mockQuery); @@ -316,6 +319,36 @@ public void testGetSingleTask() { .body("taskState", equalTo(MockProvider.EXAMPLE_HISTORIC_TASK_STATE)) .when().get(SINGLE_TASK_URL); } + @Test + public void testGetSingleTaskWithQueryParam() { + given().pathParam("id", EXAMPLE_TASK_ID) + .queryParam("withCommentAttachmentInfo", true) + .header("accept", MediaType.APPLICATION_JSON) + .then().expect().statusCode(Status.OK.getStatusCode()) + .body("id", equalTo(EXAMPLE_TASK_ID)) + .body("name", equalTo(MockProvider.EXAMPLE_TASK_NAME)) + .body("assignee", equalTo(MockProvider.EXAMPLE_TASK_ASSIGNEE_NAME)) + .body("created", equalTo(MockProvider.EXAMPLE_TASK_CREATE_TIME)) + .body("due", equalTo(MockProvider.EXAMPLE_TASK_DUE_DATE)) + .body("delegationState", equalTo(MockProvider.EXAMPLE_TASK_DELEGATION_STATE.toString())) + .body("description", equalTo(MockProvider.EXAMPLE_TASK_DESCRIPTION)) + .body("executionId", equalTo(MockProvider.EXAMPLE_TASK_EXECUTION_ID)) + .body("owner", equalTo(MockProvider.EXAMPLE_TASK_OWNER)) + .body("parentTaskId", equalTo(MockProvider.EXAMPLE_TASK_PARENT_TASK_ID)) + .body("priority", equalTo(MockProvider.EXAMPLE_TASK_PRIORITY)) + .body("processDefinitionId", equalTo(MockProvider.EXAMPLE_PROCESS_DEFINITION_ID)) + .body("processInstanceId", equalTo(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID)) + .body("taskDefinitionKey", equalTo(MockProvider.EXAMPLE_TASK_DEFINITION_KEY)) + .body("suspended", equalTo(MockProvider.EXAMPLE_TASK_SUSPENSION_STATE)) + .body("caseExecutionId", equalTo(MockProvider.EXAMPLE_CASE_EXECUTION_ID)) + .body("caseInstanceId", equalTo(MockProvider.EXAMPLE_CASE_INSTANCE_ID)) + .body("caseDefinitionId", equalTo(MockProvider.EXAMPLE_CASE_DEFINITION_ID)) + .body("tenantId", equalTo(MockProvider.EXAMPLE_TENANT_ID)) + .body("lastUpdated", equalTo(MockProvider.EXAMPLE_TASK_LAST_UPDATED)) + .body("attachment", equalTo(MockProvider.EXAMPLE_TASK_ATTACHMENT_STATE)) + .body("comment", equalTo(MockProvider.EXAMPLE_TASK_COMMENT_STATE)) + .when().get(SINGLE_TASK_URL); + } @Test @SuppressWarnings("unchecked") diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/TaskRestServiceQueryTest.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/TaskRestServiceQueryTest.java index 48d7a8eb388..a0516402dc0 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/TaskRestServiceQueryTest.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/TaskRestServiceQueryTest.java @@ -211,6 +211,32 @@ public void testSimpleTaskQuery() { assertThat(MockProvider.EXAMPLE_FORM_KEY).isEqualTo(returnedFormKey); assertThat(MockProvider.EXAMPLE_TENANT_ID).isEqualTo(returnedTenantId); + } + @Test + public void testTaskQueryWithAttachmentAndComment() { + String queryName = "name"; + + Response response = given().queryParam("name", queryName) + .queryParam("withCommentAttachmentInfo","true") + .header("accept", MediaType.APPLICATION_JSON) + .then().expect().statusCode(Status.OK.getStatusCode()) + .when().get(TASK_QUERY_URL); + + InOrder inOrder = inOrder(mockQuery); + inOrder.verify(mockQuery).taskName(queryName); + inOrder.verify(mockQuery).list(); + + String content = response.asString(); + List> instances = from(content).getList(""); + assertThat(instances).hasSize(1).as("There should be one task returned."); + assertThat(instances.get(0)).isNotNull().as("The returned task should not be null."); + + boolean returnedAttachmentsInfo = from(content).getBoolean("[0].attachment"); + boolean returnedCommentsInfo = from(content).getBoolean("[0].comment"); + + assertThat(MockProvider.EXAMPLE_TASK_ATTACHMENT_STATE).isEqualTo(returnedAttachmentsInfo); + assertThat(MockProvider.EXAMPLE_TASK_COMMENT_STATE).isEqualTo(returnedCommentsInfo); + } @Test @@ -482,6 +508,7 @@ private Map getCompleteStringQueryParameters() { parameters.put("assignee", "anAssignee"); parameters.put("assigneeLike", "anAssigneeLike"); parameters.put("candidateGroup", "aCandidateGroup"); + parameters.put("candidateGroupLike", "aCandidateGroupLike"); parameters.put("candidateUser", "aCandidate"); parameters.put("includeAssignedTasks", "false"); parameters.put("taskId", "aTaskId"); @@ -521,6 +548,7 @@ private Map getCompleteBooleanQueryParameters() { parameters.put("withCandidateUsers", true); parameters.put("withoutCandidateUsers", true); parameters.put("withoutDueDate", true); + parameters.put("withCommentAttachmentInfo", true); return parameters; } @@ -539,6 +567,7 @@ private void verifyStringParameterQueryInvocations() { verify(mockQuery).taskAssignee(stringQueryParameters.get("assignee")); verify(mockQuery).taskAssigneeLike(stringQueryParameters.get("assigneeLike")); verify(mockQuery).taskCandidateGroup(stringQueryParameters.get("candidateGroup")); + verify(mockQuery).taskCandidateGroupLike(stringQueryParameters.get("candidateGroupLike")); verify(mockQuery).taskCandidateUser(stringQueryParameters.get("candidateUser")); verify(mockQuery).taskDefinitionKey(stringQueryParameters.get("taskDefinitionKey")); verify(mockQuery).taskDefinitionKeyLike(stringQueryParameters.get("taskDefinitionKeyLike")); @@ -586,6 +615,7 @@ private void verifyBooleanParameterQueryInvocation() { verify(mockQuery).withCandidateUsers(); verify(mockQuery).withoutCandidateUsers(); verify(mockQuery).withoutDueDate(); + verify(mockQuery).withCommentAttachmentInfo(); } @Test diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockJobBuilder.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockJobBuilder.java index c2969c8f8ed..21686316fd0 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockJobBuilder.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockJobBuilder.java @@ -39,6 +39,7 @@ public class MockJobBuilder { protected String tenantId; protected Date createTime; protected String failedActivityId; + protected String batchId; public MockJobBuilder id(String id) { this.id = id; @@ -110,6 +111,11 @@ public MockJobBuilder failedActivityId(String failedActivityId) { return this; } + public MockJobBuilder batchId(String batchId) { + this.batchId = batchId; + return this; + } + public Job build() { Job mockJob = mock(Job.class); when(mockJob.getId()).thenReturn(id); @@ -126,6 +132,7 @@ public Job build() { when(mockJob.getTenantId()).thenReturn(tenantId); when(mockJob.getCreateTime()).thenReturn(createTime); when(mockJob.getFailedActivityId()).thenReturn(failedActivityId); + when(mockJob.getBatchId()).thenReturn(batchId); return mockJob; } diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockProvider.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockProvider.java index 2f054bd8feb..15934942e23 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockProvider.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockProvider.java @@ -198,6 +198,10 @@ public abstract class MockProvider { public static final String EXAMPLE_TASK_DEFINITION_KEY = "aTaskDefinitionKey"; public static final boolean EXAMPLE_TASK_SUSPENSION_STATE = false; + public static final boolean EXAMPLE_TASK_ATTACHMENT_STATE = false; + + public static final boolean EXAMPLE_TASK_COMMENT_STATE = false; + // task comment public static final String EXAMPLE_TASK_COMMENT_ID = "aTaskCommentId"; public static final String EXAMPLE_TASK_COMMENT_FULL_MESSAGE = "aTaskCommentFullMessage"; @@ -1057,7 +1061,11 @@ public static MockTaskBuilder mockTask() { .caseExecutionId(EXAMPLE_CASE_EXECUTION_ID) .formKey(EXAMPLE_FORM_KEY) .operatonFormRef(EXAMPLE_FORM_KEY, EXAMPLE_FORM_REF_BINDING, EXAMPLE_FORM_REF_VERSION) - .tenantId(EXAMPLE_TENANT_ID).taskState(EXAMPLE_HISTORIC_TASK_STATE); + .tenantId(EXAMPLE_TENANT_ID) + .taskState(EXAMPLE_HISTORIC_TASK_STATE) + .tenantId(EXAMPLE_TENANT_ID) + .hasAttachment(EXAMPLE_TASK_ATTACHMENT_STATE) + .hasComment(EXAMPLE_TASK_COMMENT_STATE); } public static List createMockTasks() { @@ -1860,7 +1868,8 @@ public static MockJobBuilder mockJob() { .priority(EXAMPLE_JOB_PRIORITY) .jobDefinitionId(EXAMPLE_JOB_DEFINITION_ID) .createTime(DateTimeUtil.parseDate(EXAMPLE_JOB_CREATE_TIME)) - .failedActivityId(EXAMPLE_JOB_FAILED_ACTIVITY_ID); + .failedActivityId(EXAMPLE_JOB_FAILED_ACTIVITY_ID) + .batchId(EXAMPLE_BATCH_ID); } public static List createMockJobs() { @@ -2183,6 +2192,7 @@ public static HistoricProcessInstance createMockHistoricProcessInstance(String t when(mock.getCaseInstanceId()).thenReturn(EXAMPLE_HISTORIC_PROCESS_INSTANCE_CASE_INSTANCE_ID); when(mock.getTenantId()).thenReturn(tenantId); when(mock.getState()).thenReturn(EXAMPLE_HISTORIC_PROCESS_INSTANCE_STATE); + when(mock.getRestartedProcessInstanceId()).thenReturn(EXAMPLE_PROCESS_INSTANCE_ID); return mock; } @@ -2976,6 +2986,7 @@ public static HistoricJobLog createMockHistoricJobLog(String tenantId) { when(mock.getTenantId()).thenReturn(tenantId); when(mock.getRootProcessInstanceId()).thenReturn(EXAMPLE_HISTORIC_JOB_LOG_ROOT_PROC_INST_ID); when(mock.getHostname()).thenReturn(EXAMPLE_HISTORIC_JOB_LOG_HOSTNAME); + when(mock.getBatchId()).thenReturn(EXAMPLE_BATCH_ID); when(mock.isCreationLog()).thenReturn(EXAMPLE_HISTORIC_JOB_LOG_IS_CREATION_LOG); when(mock.isFailureLog()).thenReturn(EXAMPLE_HISTORIC_JOB_LOG_IS_FAILURE_LOG); diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockTaskBuilder.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockTaskBuilder.java index d80ddbe5268..95b9ebaf007 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockTaskBuilder.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/helper/MockTaskBuilder.java @@ -50,6 +50,11 @@ public class MockTaskBuilder { private String formKey; private OperatonFormRef operatonFormRef; private String tenantId; + private boolean hasAttachment; + + private boolean hasComment; + + private String taskState; @@ -170,6 +175,16 @@ public MockTaskBuilder taskState(String taskState) { return this; } + public MockTaskBuilder hasAttachment(boolean hasAttachment) { + this.hasAttachment = hasAttachment; + return this; + } + + public MockTaskBuilder hasComment(boolean hasComment) { + this.hasComment = hasComment; + return this; + } + public Task build() { Task mockTask = mock(Task.class); when(mockTask.getId()).thenReturn(id); @@ -195,6 +210,8 @@ public Task build() { when(mockTask.getOperatonFormRef()).thenReturn(operatonFormRef); when(mockTask.getTenantId()).thenReturn(tenantId); when(mockTask.getTaskState()).thenReturn(taskState); + when(mockTask.hasAttachment()).thenReturn(hasAttachment); + when(mockTask.hasComment()).thenReturn(hasComment); return mockTask; } diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricJobLogRestServiceInteractionTest.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricJobLogRestServiceInteractionTest.java index 42339da7666..ddac95bc9ac 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricJobLogRestServiceInteractionTest.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricJobLogRestServiceInteractionTest.java @@ -106,6 +106,7 @@ public void testSimpleHistoricJobLogGet() { .body("tenantId", equalTo(MockProvider.EXAMPLE_TENANT_ID)) .body("hostname", equalTo(MockProvider.EXAMPLE_HISTORIC_JOB_LOG_HOSTNAME)) .body("rootProcessInstanceId", equalTo(MockProvider.EXAMPLE_HISTORIC_JOB_LOG_ROOT_PROC_INST_ID)) + .body("batchId", equalTo(MockProvider.EXAMPLE_BATCH_ID)) .body("creationLog", equalTo(MockProvider.EXAMPLE_HISTORIC_JOB_LOG_IS_CREATION_LOG)) .body("failureLog", equalTo(MockProvider.EXAMPLE_HISTORIC_JOB_LOG_IS_FAILURE_LOG)) .body("successLog", equalTo(MockProvider.EXAMPLE_HISTORIC_JOB_LOG_IS_SUCCESS_LOG)) diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricProcessInstanceRestServiceInteractionTest.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricProcessInstanceRestServiceInteractionTest.java index 5a853c12e63..748b78af686 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricProcessInstanceRestServiceInteractionTest.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricProcessInstanceRestServiceInteractionTest.java @@ -123,6 +123,7 @@ public void testGetSingleInstance() { String returnedCaseInstanceId = from(content).getString("caseInstanceId"); String returnedTenantId = from(content).getString("tenantId"); String returnedState = from(content).getString("state"); + String restartedProcessInstanceId = from(content).getString("restartedProcessInstanceId"); Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID, returnedProcessInstanceId); Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_BUSINESS_KEY, returnedProcessInstanceBusinessKey); @@ -139,6 +140,7 @@ public void testGetSingleInstance() { Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_CASE_INSTANCE_ID, returnedCaseInstanceId); Assert.assertEquals(MockProvider.EXAMPLE_TENANT_ID, returnedTenantId); Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STATE, returnedState); + Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID, restartedProcessInstanceId); } diff --git a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricProcessInstanceRestServiceQueryTest.java b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricProcessInstanceRestServiceQueryTest.java index e63bf12bbb9..64ae1f81078 100644 --- a/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricProcessInstanceRestServiceQueryTest.java +++ b/engine-rest/engine-rest/src/test/java/org/operaton/bpm/engine/rest/history/HistoricProcessInstanceRestServiceQueryTest.java @@ -73,6 +73,8 @@ public class HistoricProcessInstanceRestServiceQueryTest extends AbstractRestSer protected static final String QUERY_PARAM_EXECUTED_ACTIVITY_AFTER = "executedActivityAfter"; protected static final String QUERY_PARAM_EXECUTED_ACTIVITY_IDS = "executedActivityIdIn"; protected static final String QUERY_PARAM_ACTIVE_ACTIVITY_IDS = "activeActivityIdIn"; + protected static final String QUERY_PARAM_INCIDENT_IDS = "incidentIdIn"; + protected static final String QUERY_PARAM_ACTIVE_OR_FAILING_ACTIVITY_IDS = "activityIdIn"; @ClassRule public static TestContainerRule rule = new TestContainerRule(); @@ -429,6 +431,7 @@ public void testSimpleHistoricProcessQuery() { String returnedCaseInstanceId = from(content).getString("[0].caseInstanceId"); String returnedTenantId = from(content).getString("[0].tenantId"); String returnedState = from(content).getString("[0].state"); + String restartedProcessInstanceId = from(content).getString("[0].restartedProcessInstanceId"); Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID, returnedProcessInstanceId); Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_BUSINESS_KEY, returnedProcessInstanceBusinessKey); @@ -449,6 +452,7 @@ public void testSimpleHistoricProcessQuery() { Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_CASE_INSTANCE_ID, returnedCaseInstanceId); Assert.assertEquals(MockProvider.EXAMPLE_TENANT_ID, returnedTenantId); Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STATE, returnedState); + Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID, restartedProcessInstanceId); } @Test @@ -2315,5 +2319,60 @@ public void testQueryByRootProcessInstancesAsPost() { verify(mockedQuery).rootProcessInstances(); } + @Test + public void testQueryByIncidentIdIn() { + given() + .queryParam(QUERY_PARAM_INCIDENT_IDS, "1,2") + .then().expect() + .statusCode(Status.OK.getStatusCode()) + .when() + .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL); + + verify(mockedQuery).incidentIdIn("1", "2"); + } + + @Test + public void testQueryByIncidentIdInAsPost() { + Map> parameters = new HashMap>(); + parameters.put(QUERY_PARAM_INCIDENT_IDS, Arrays.asList("1", "2")); + + given() + .contentType(POST_JSON_CONTENT_TYPE) + .body(parameters) + .then().expect() + .statusCode(Status.OK.getStatusCode()) + .when() + .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL); + + verify(mockedQuery).incidentIdIn("1", "2"); + } + + @Test + public void testQueryByActivityIdIn() { + given() + .queryParam(QUERY_PARAM_ACTIVE_OR_FAILING_ACTIVITY_IDS, "1,2") + .then().expect() + .statusCode(Status.OK.getStatusCode()) + .when() + .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL); + + verify(mockedQuery).activityIdIn("1", "2"); + } + + @Test + public void testQueryByActivityIdInAsPost() { + Map> parameters = new HashMap>(); + parameters.put(QUERY_PARAM_ACTIVE_OR_FAILING_ACTIVITY_IDS, Arrays.asList("1", "2")); + + given() + .contentType(POST_JSON_CONTENT_TYPE) + .body(parameters) + .then().expect() + .statusCode(Status.OK.getStatusCode()) + .when() + .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL); + + verify(mockedQuery).activityIdIn("1", "2"); + } } diff --git a/engine/src/main/java/org/operaton/bpm/engine/history/HistoricJobLog.java b/engine/src/main/java/org/operaton/bpm/engine/history/HistoricJobLog.java index 7fece9fe197..e928463464a 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/history/HistoricJobLog.java +++ b/engine/src/main/java/org/operaton/bpm/engine/history/HistoricJobLog.java @@ -176,4 +176,10 @@ public interface HistoricJobLog { /** The time the historic job log will be removed. */ Date getRemovalTime(); + /** + * Returns the ID of the batch associated with the job or {@code null} if no batch is associated with the job. + * @return the ID of the batch associated with the job + */ + String getBatchId(); + } diff --git a/engine/src/main/java/org/operaton/bpm/engine/history/HistoricProcessInstance.java b/engine/src/main/java/org/operaton/bpm/engine/history/HistoricProcessInstance.java index 8eb1422c0de..0b827cd69d6 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/history/HistoricProcessInstance.java +++ b/engine/src/main/java/org/operaton/bpm/engine/history/HistoricProcessInstance.java @@ -118,4 +118,9 @@ public interface HistoricProcessInstance { * STATE_INTERNALLY_TERMINATED - terminated internally, for instance by terminating boundary event */ String getState(); + + /** + * The id of the original process instance which was restarted. + */ + String getRestartedProcessInstanceId(); } diff --git a/engine/src/main/java/org/operaton/bpm/engine/history/HistoricProcessInstanceQuery.java b/engine/src/main/java/org/operaton/bpm/engine/history/HistoricProcessInstanceQuery.java index 62fe37891ce..8742c628147 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/history/HistoricProcessInstanceQuery.java +++ b/engine/src/main/java/org/operaton/bpm/engine/history/HistoricProcessInstanceQuery.java @@ -127,6 +127,11 @@ public interface HistoricProcessInstanceQuery extends Query processInstanceIds; protected List instructions; protected String processDefinitionId; @@ -114,6 +116,12 @@ public ModificationBuilder processInstanceQuery(ProcessInstanceQuery processInst return this; } + @Override + public ModificationBuilder historicProcessInstanceQuery(HistoricProcessInstanceQuery historicProcessInstanceQuery) { + this.historicProcessInstanceQuery = historicProcessInstanceQuery; + return this; + } + @Override public ModificationBuilder skipCustomListeners() { this.skipCustomListeners = true; @@ -153,6 +161,10 @@ public ProcessInstanceQuery getProcessInstanceQuery() { return processInstanceQuery; } + public HistoricProcessInstanceQuery getHistoricProcessInstanceQuery() { + return historicProcessInstanceQuery; + } + public List getProcessInstanceIds() { return processInstanceIds; } diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/ProcessInstantiationBuilderImpl.java b/engine/src/main/java/org/operaton/bpm/engine/impl/ProcessInstantiationBuilderImpl.java index 9e226ecdae2..d48ff2e1e39 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/ProcessInstantiationBuilderImpl.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/ProcessInstantiationBuilderImpl.java @@ -50,6 +50,8 @@ public class ProcessInstantiationBuilderImpl implements ProcessInstantiationBuil protected String processDefinitionTenantId; protected boolean isProcessDefinitionTenantIdSet = false; + protected String restartedProcessInstanceId; + protected ProcessInstanceModificationBuilderImpl modificationBuilder; protected ProcessInstantiationBuilderImpl(CommandExecutor commandExecutor) { @@ -206,6 +208,14 @@ public void setModificationBuilder(ProcessInstanceModificationBuilderImpl modifi this.modificationBuilder = modificationBuilder; } + public void setRestartedProcessInstanceId(String restartedProcessInstanceId){ + this.restartedProcessInstanceId = restartedProcessInstanceId; + } + + public String getRestartedProcessInstanceId(){ + return restartedProcessInstanceId; + } + public static ProcessInstantiationBuilder createProcessInstanceById(CommandExecutor commandExecutor, String processDefinitionId) { ProcessInstantiationBuilderImpl builder = new ProcessInstantiationBuilderImpl(commandExecutor); builder.processDefinitionId = processDefinitionId; diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/TaskQueryImpl.java b/engine/src/main/java/org/operaton/bpm/engine/impl/TaskQueryImpl.java index a72999e9d5c..882ad32fe5e 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/TaskQueryImpl.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/TaskQueryImpl.java @@ -44,6 +44,7 @@ import org.operaton.bpm.engine.task.Task; import org.operaton.bpm.engine.task.TaskQuery; import org.operaton.bpm.engine.variable.type.ValueType; +import org.operaton.bpm.engine.impl.history.HistoryLevel; /** * @author Joram Barrez @@ -113,6 +114,7 @@ public class TaskQueryImpl extends AbstractQuery implements Tas protected DelegationState delegationState; protected String candidateUser; protected String candidateGroup; + protected String candidateGroupLike; protected List candidateGroups; protected Boolean withCandidateGroups; protected Boolean withoutCandidateGroups; @@ -175,6 +177,7 @@ public class TaskQueryImpl extends AbstractQuery implements Tas // or query ///////////////////////////// protected List queries = new ArrayList<>(Arrays.asList(this)); protected boolean isOrQueryActive = false; + protected boolean withCommentAttachmentInfo; public TaskQueryImpl() { } @@ -449,6 +452,18 @@ public TaskQuery taskCandidateGroupExpression(String candidateGroupExpression) { return this; } + @Override + public TaskQuery taskCandidateGroupLike(String candidateGroupLike) { + ensureNotNull("Candidate group like", candidateGroupLike); + + if (!isOrQueryActive && (candidateUser != null || expressions.containsKey("taskCandidateUser"))) { + throw new ProcessEngineException("Invalid query usage: cannot set both candidateGroupLike and candidateUser"); + } + + this.candidateGroupLike = candidateGroupLike; + return this; + } + @Override public TaskQuery taskCandidateGroupIn(List candidateGroups) { ensureNotEmpty("Candidate group list", candidateGroups); @@ -480,10 +495,11 @@ public TaskQuery taskCandidateGroupInExpression(String candidateGroupsExpression @Override public TaskQuery includeAssignedTasks() { - if (candidateUser == null && candidateGroup == null && candidateGroups == null && !isWithCandidateGroups() && !isWithoutCandidateGroups() && !isWithCandidateUsers() && !isWithoutCandidateUsers() + if (candidateUser == null && candidateGroup == null && candidateGroupLike == null && candidateGroups == null + && !isWithCandidateGroups() && !isWithoutCandidateGroups() && !isWithCandidateUsers() && !isWithoutCandidateUsers() && !expressions.containsKey("taskCandidateUser") && !expressions.containsKey("taskCandidateGroup") && !expressions.containsKey("taskCandidateGroupIn")) { - throw new ProcessEngineException("Invalid query usage: candidateUser, candidateGroup, candidateGroupIn, withCandidateGroups, withoutCandidateGroups, withCandidateUsers, withoutCandidateUsers has to be called before 'includeAssignedTasks'."); + throw new ProcessEngineException("Invalid query usage: candidateUser, candidateGroup, candidateGroupLike, candidateGroupIn, withCandidateGroups, withoutCandidateGroups, withCandidateUsers, withoutCandidateUsers has to be called before 'includeAssignedTasks'."); } includeAssignedTasks = true; @@ -1088,6 +1104,12 @@ protected boolean hasExcludingConditions() { || CompareUtil.elementIsNotContainedInArray(processInstanceBusinessKey, processInstanceBusinessKeys); } + @Override + public TaskQuery withCommentAttachmentInfo() { + this.withCommentAttachmentInfo = true; + return this; + } + public List getCandidateGroups() { if (cachedCandidateGroups != null) { return cachedCandidateGroups; @@ -1441,6 +1463,13 @@ public List executeList(CommandContext commandContext, Page page) { } } + if (withCommentAttachmentInfo && !Context.getProcessEngineConfiguration().getHistoryLevel().equals(HistoryLevel.HISTORY_LEVEL_NONE)) { + for (Task task : taskList) { + // verify attachment and comments exists for the task + ((TaskEntity) task).initializeAttachmentAndComments(); + } + } + return taskList; } @@ -1563,6 +1592,10 @@ public String getCandidateGroup() { return candidateGroup; } + public String getCandidateGroupLike() { + return candidateGroupLike; + } + public boolean isIncludeAssignedTasks() { return includeAssignedTasks != null ? includeAssignedTasks : false; } @@ -1914,6 +1947,13 @@ else if (this.getCandidateGroup() != null) { extendedQuery.taskCandidateGroup(this.getCandidateGroup()); } + if (extendingQuery.getCandidateGroupLike() != null) { + extendedQuery.taskCandidateGroupLike(extendingQuery.getCandidateGroupLike()); + } + else if (this.getCandidateGroupLike() != null) { + extendedQuery.taskCandidateGroupLike(this.getCandidateGroupLike()); + } + if (extendingQuery.isWithCandidateGroups() || this.isWithCandidateGroups()) { extendedQuery.withCandidateGroups(); } diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/cfg/ProcessEngineConfigurationImpl.java b/engine/src/main/java/org/operaton/bpm/engine/impl/cfg/ProcessEngineConfigurationImpl.java index 25c5d3f454b..355e6150d7d 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/cfg/ProcessEngineConfigurationImpl.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/cfg/ProcessEngineConfigurationImpl.java @@ -1943,6 +1943,7 @@ public static void initSqlSessionFactoryProperties(Properties properties, String properties.put("authJoin1Separator", DbSqlSessionFactory.databaseSpecificAuth1JoinSeparator.get(databaseType)); properties.put("extractTimeUnitFromDate", DbSqlSessionFactory.databaseSpecificExtractTimeUnitFromDate.get(databaseType)); + properties.put("authCheckMethodSuffix", DbSqlSessionFactory.databaseSpecificAuthCheckMethodSuffix.getOrDefault(databaseType, "")); Map constants = DbSqlSessionFactory.dbSpecificConstants.get(databaseType); for (Entry entry : constants.entrySet()) { diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/AbstractModificationCmd.java b/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/AbstractModificationCmd.java index fd49a930195..e89e060e7fa 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/AbstractModificationCmd.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/AbstractModificationCmd.java @@ -23,6 +23,7 @@ import java.util.Set; import org.operaton.bpm.engine.history.UserOperationLogEntry; +import org.operaton.bpm.engine.impl.HistoricProcessInstanceQueryImpl; import org.operaton.bpm.engine.impl.ModificationBuilderImpl; import org.operaton.bpm.engine.impl.ProcessInstanceQueryImpl; import org.operaton.bpm.engine.impl.interceptor.Command; @@ -53,6 +54,12 @@ protected Collection collectProcessInstanceIds() { collectedProcessInstanceIds.addAll(processInstanceQuery.listIds()); } + final HistoricProcessInstanceQueryImpl historicProcessInstanceQuery = + (HistoricProcessInstanceQueryImpl) builder.getHistoricProcessInstanceQuery(); + if(historicProcessInstanceQuery != null) { + collectedProcessInstanceIds.addAll(historicProcessInstanceQuery.listIds()); + } + return collectedProcessInstanceIds; } diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/RestartProcessInstancesCmd.java b/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/RestartProcessInstancesCmd.java index a97c7335941..2f56f656ed8 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/RestartProcessInstancesCmd.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/RestartProcessInstancesCmd.java @@ -103,6 +103,8 @@ public Void execute(final CommandContext commandContext) { getProcessInstantiationBuilder(commandExecutor, processDefinitionId); applyProperties(instantiationBuilder, processDefinition, historicProcessInstance); + instantiationBuilder.setRestartedProcessInstanceId(processInstanceId); + ProcessInstanceModificationBuilderImpl modificationBuilder = instantiationBuilder.getModificationBuilder(); @@ -167,7 +169,6 @@ protected void applyProperties(ProcessInstantiationBuilderImpl instantiationBuil if (!builder.isWithoutBusinessKey()) { instantiationBuilder.businessKey(processInstance.getBusinessKey()); } - } protected VariableMap collectVariables(CommandContext commandContext, diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/StartProcessInstanceAtActivitiesCmd.java b/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/StartProcessInstanceAtActivitiesCmd.java index e083f276b05..abb57e0a6ef 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/StartProcessInstanceAtActivitiesCmd.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/cmd/StartProcessInstanceAtActivitiesCmd.java @@ -79,6 +79,8 @@ public ProcessInstanceWithVariables execute(CommandContext commandContext) { processInstance.setTenantId(instantiationBuilder.getTenantId()); } + processInstance.setRestartedProcessInstanceId(instantiationBuilder.getRestartedProcessInstanceId()); + processInstance.setSkipCustomListeners(modificationBuilder.isSkipCustomListeners()); VariableMap variables = modificationBuilder.getProcessVariables(); diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/db/sql/DbSqlSessionFactory.java b/engine/src/main/java/org/operaton/bpm/engine/impl/db/sql/DbSqlSessionFactory.java index 3d41397bf96..79365091770 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/db/sql/DbSqlSessionFactory.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/db/sql/DbSqlSessionFactory.java @@ -106,6 +106,8 @@ public class DbSqlSessionFactory implements SessionFactory { public static final Map databaseSpecificAuth1JoinSeparator = new HashMap<>(); public static final Map databaseSpecificExtractTimeUnitFromDate = new HashMap<>(); + public static final Map databaseSpecificAuthCheckMethodSuffix = new HashMap<>(); + /* * On SQL server, the overall maximum number of parameters in a prepared statement @@ -729,6 +731,7 @@ public class DbSqlSessionFactory implements SessionFactory { databaseSpecificAuthJoinStart.put(MSSQL, defaultAuthOnStart); databaseSpecificAuthJoinEnd.put(MSSQL, defaultAuthOnEnd); databaseSpecificAuthJoinSeparator.put(MSSQL, defaultAuthOnSeparator); + databaseSpecificAuthCheckMethodSuffix.put(MSSQL, "_mssql"); databaseSpecificAuth1JoinStart.put(MSSQL, defaultAuthOnStart); databaseSpecificAuth1JoinEnd.put(MSSQL, defaultAuthOnEnd); diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/history/event/HistoricJobLogEvent.java b/engine/src/main/java/org/operaton/bpm/engine/impl/history/event/HistoricJobLogEvent.java index 486b5f2bdc0..d963e3d2840 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/history/event/HistoricJobLogEvent.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/history/event/HistoricJobLogEvent.java @@ -63,6 +63,8 @@ public class HistoricJobLogEvent extends HistoryEvent { protected String hostname; + protected String batchId; + public Date getTimestamp() { return timestamp; } @@ -235,4 +237,11 @@ public void setFailedActivityId(String failedActivityId) { this.failedActivityId = failedActivityId; } + public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } } diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/history/event/HistoricProcessInstanceEventEntity.java b/engine/src/main/java/org/operaton/bpm/engine/impl/history/event/HistoricProcessInstanceEventEntity.java index 35492493ae4..bcba6c0df41 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/history/event/HistoricProcessInstanceEventEntity.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/history/event/HistoricProcessInstanceEventEntity.java @@ -54,6 +54,9 @@ public class HistoricProcessInstanceEventEntity extends HistoricScopeInstanceEve protected String state; + /** completed HPI that has been restarted */ + protected String restartedProcessInstanceId; + // getters / setters //////////////////////////////////////// public String getEndActivityId() { @@ -128,6 +131,14 @@ public void setState(String state) { this.state = state; } + public String getRestartedProcessInstanceId() { + return restartedProcessInstanceId; + } + + public void setRestartedProcessInstanceId(String restartedProcessInstanceId) { + this.restartedProcessInstanceId = restartedProcessInstanceId; + } + @Override public String toString() { return this.getClass().getSimpleName() @@ -149,6 +160,7 @@ public String toString() { + ", processDefinitionId=" + processDefinitionId + ", processInstanceId=" + processInstanceId + ", tenantId=" + tenantId + + ", restartedProcessInstanceId=" + restartedProcessInstanceId + "]"; } diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/history/producer/DefaultHistoryEventProducer.java b/engine/src/main/java/org/operaton/bpm/engine/impl/history/producer/DefaultHistoryEventProducer.java index d864a020b5e..fad33d4caf6 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/history/producer/DefaultHistoryEventProducer.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/history/producer/DefaultHistoryEventProducer.java @@ -204,6 +204,7 @@ protected void initProcessInstanceEvent(HistoricProcessInstanceEventEntity evt, evt.setCaseInstanceId(caseInstanceId); evt.setTenantId(tenantId); evt.setRootProcessInstanceId(execution.getRootProcessInstanceId()); + evt.setRestartedProcessInstanceId(execution.getRestartedProcessInstanceId()); if (execution.getSuperCaseExecution() != null) { evt.setSuperCaseInstanceId(execution.getSuperCaseExecution().getCaseInstanceId()); @@ -1124,6 +1125,7 @@ protected void initHistoricJobLogEvent(HistoricJobLogEventEntity evt, Job job, H JobEntity jobEntity = (JobEntity) job; evt.setJobId(jobEntity.getId()); + evt.setBatchId(jobEntity.getBatchId()); evt.setJobDueDate(jobEntity.getDuedate()); evt.setJobRetries(jobEntity.getRetries()); evt.setJobPriority(jobEntity.getPriority()); diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/jobexecutor/JobDeclaration.java b/engine/src/main/java/org/operaton/bpm/engine/impl/jobexecutor/JobDeclaration.java index 3f5ed8e145f..956aaefc531 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/jobexecutor/JobDeclaration.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/jobexecutor/JobDeclaration.java @@ -20,8 +20,9 @@ import java.io.Serializable; import java.util.Date; - import org.operaton.bpm.engine.ProcessEngineConfiguration; +import org.operaton.bpm.engine.impl.batch.BatchEntity; +import org.operaton.bpm.engine.impl.batch.BatchJobContext; import org.operaton.bpm.engine.impl.context.Context; import org.operaton.bpm.engine.impl.core.variable.mapping.value.ParameterValueProvider; import org.operaton.bpm.engine.impl.persistence.entity.ExecutionEntity; @@ -77,6 +78,15 @@ public T createJobInstance(S context) { String jobDefinitionId = resolveJobDefinitionId(context); job.setJobDefinitionId(jobDefinitionId); + //set batch id for monitor and seed jobs (BatchEntity) and batch execution jobs (BatchJobContext) + if (context instanceof BatchEntity) { + BatchEntity batch = ((BatchEntity) context); + job.setBatchId(batch.getId()); + } else if (context instanceof BatchJobContext) { + BatchJobContext batchJobContext = (BatchJobContext) context; + job.setBatchId(batchJobContext.getBatch().getId()); + } + if(jobDefinitionId != null) { JobDefinitionEntity jobDefinition = Context.getCommandContext() diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/json/JsonTaskQueryConverter.java b/engine/src/main/java/org/operaton/bpm/engine/impl/json/JsonTaskQueryConverter.java index 00b6f3f6ffa..46fd2f2f482 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/json/JsonTaskQueryConverter.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/json/JsonTaskQueryConverter.java @@ -62,6 +62,7 @@ public class JsonTaskQueryConverter extends JsonObjectConverter { public static final String DELEGATION_STATE = "delegationState"; public static final String CANDIDATE_USER = "candidateUser"; public static final String CANDIDATE_GROUP = "candidateGroup"; + public static final String CANDIDATE_GROUP_LIKE = "candidateGroupLike"; public static final String CANDIDATE_GROUPS = "candidateGroups"; public static final String WITH_CANDIDATE_GROUPS = "withCandidateGroups"; public static final String WITHOUT_CANDIDATE_GROUPS = "withoutCandidateGroups"; @@ -166,6 +167,7 @@ public JsonObject toJsonObject(TaskQuery taskQuery, boolean isOrQueryActive) { JsonUtil.addField(json, DELEGATION_STATE, query.getDelegationStateString()); JsonUtil.addField(json, CANDIDATE_USER, query.getCandidateUser()); JsonUtil.addField(json, CANDIDATE_GROUP, query.getCandidateGroup()); + JsonUtil.addField(json, CANDIDATE_GROUP_LIKE, query.getCandidateGroupLike()); JsonUtil.addListField(json, CANDIDATE_GROUPS, query.getCandidateGroupsInternal()); JsonUtil.addDefaultField(json, WITH_CANDIDATE_GROUPS, false, query.isWithCandidateGroups()); JsonUtil.addDefaultField(json, WITHOUT_CANDIDATE_GROUPS, false, query.isWithoutCandidateGroups()); @@ -363,6 +365,9 @@ protected TaskQuery toObject(JsonObject json, boolean isOrQuery) { if (json.has(CANDIDATE_GROUP)) { query.taskCandidateGroup(JsonUtil.getString(json, CANDIDATE_GROUP)); } + if (json.has(CANDIDATE_GROUP_LIKE)) { + query.taskCandidateGroupLike(JsonUtil.getString(json, CANDIDATE_GROUP_LIKE)); + } if (json.has(CANDIDATE_GROUPS) && !json.has(CANDIDATE_USER) && !json.has(CANDIDATE_GROUP)) { query.taskCandidateGroupIn(getList(JsonUtil.getArray(json, CANDIDATE_GROUPS))); } diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/ExecutionEntity.java b/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/ExecutionEntity.java index 3c8c757ac23..66dae261461 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/ExecutionEntity.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/ExecutionEntity.java @@ -234,6 +234,11 @@ public class ExecutionEntity extends PvmExecutionImpl implements Execution, Proc */ protected String superCaseExecutionId; + /** + * Completed HPI that is being restarted through this ExecutionEntity + */ + protected String restartedProcessInstanceId; + /** * Contains observers which are observe the execution. * @since 7.6 @@ -970,6 +975,14 @@ public void setSuperCaseExecutionId(String superCaseExecutionId) { this.superCaseExecutionId = superCaseExecutionId; } + public String getRestartedProcessInstanceId(){ + return restartedProcessInstanceId; + } + + public void setRestartedProcessInstanceId(String restartedProcessInstanceId){ + this.restartedProcessInstanceId = restartedProcessInstanceId; + } + @Override public CaseExecutionEntity getSuperCaseExecution() { ensureSuperCaseExecutionInitialized(); diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/JobEntity.java b/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/JobEntity.java index 9a6db0586ac..fa061d82a93 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/JobEntity.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/JobEntity.java @@ -114,6 +114,8 @@ public abstract class JobEntity extends AcquirableJobEntity protected Map persistedDependentEntities; + protected String batchId; + public void execute(CommandContext commandContext) { if (executionId != null) { ExecutionEntity execution = getExecution(); @@ -705,6 +707,14 @@ public void setFailedActivityId(String failedActivityId) { this.failedActivityId = failedActivityId; } + public String getBatchId() { + return batchId; + } + + public void setBatchId(String batchId) { + this.batchId = batchId; + } + @Override public String toString() { return this.getClass().getSimpleName() @@ -726,6 +736,7 @@ public String toString() { + ", deploymentId=" + deploymentId + ", priority=" + priority + ", tenantId=" + tenantId + + ", batchId=" + batchId + "]"; } diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/TaskEntity.java b/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/TaskEntity.java index 075ae2b129b..862d7c052c1 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/TaskEntity.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/persistence/entity/TaskEntity.java @@ -162,6 +162,8 @@ public class TaskEntity extends AbstractVariableScope implements Task, DelegateT protected boolean isFormKeyInitialized = false; protected String formKey; protected OperatonFormRef operatonFormRef; + protected boolean attachmentExists; + protected boolean commentExists; @SuppressWarnings({ "unchecked" }) protected transient VariableStore variableStore @@ -1462,6 +1464,10 @@ public void initializeFormKey() { } } } + public void initializeAttachmentAndComments(){ + this.attachmentExists = !Context.getCommandContext().getAttachmentManager().findAttachmentsByTaskId(id).isEmpty(); + this.commentExists = !Context.getCommandContext().getCommentManager().findCommentsByTaskId(id).isEmpty(); + } @Override public String getFormKey() { @@ -1780,7 +1786,14 @@ public void bpmnError(String errorCode, String errorMessage, Map throw ProcessEngineLogger.CMD_LOGGER.exceptionBpmnErrorPropagationFailed(errorCode, ex); } } - + @Override + public boolean hasAttachment() { + return attachmentExists; + } + @Override + public boolean hasComment() { + return commentExists; + } public void escalation(String escalationCode, Map variables) { ensureTaskActive(); ActivityExecution activityExecution = getExecution(); diff --git a/engine/src/main/java/org/operaton/bpm/engine/impl/test/ProcessEngineAssert.java b/engine/src/main/java/org/operaton/bpm/engine/impl/test/ProcessEngineAssert.java index 0d13878bcfa..3d1586d03c7 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/impl/test/ProcessEngineAssert.java +++ b/engine/src/main/java/org/operaton/bpm/engine/impl/test/ProcessEngineAssert.java @@ -16,8 +16,6 @@ */ package org.operaton.bpm.engine.impl.test; -import junit.framework.AssertionFailedError; - import org.operaton.bpm.engine.ProcessEngine; import org.operaton.bpm.engine.runtime.ProcessInstance; @@ -31,7 +29,7 @@ public static void assertProcessEnded(ProcessEngine processEngine, String proces .singleResult(); if (processInstance!=null) { - throw new AssertionFailedError("expected finished process instance '"+processInstanceId+"' but it was still in the db"); + throw new AssertionError("expected finished process instance '"+processInstanceId+"' but it was still in the db"); } } } diff --git a/engine/src/main/java/org/operaton/bpm/engine/runtime/Job.java b/engine/src/main/java/org/operaton/bpm/engine/runtime/Job.java index bb1ebc37273..a443927a02b 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/runtime/Job.java +++ b/engine/src/main/java/org/operaton/bpm/engine/runtime/Job.java @@ -119,4 +119,15 @@ public interface Job { /** The date/time when this job has been created */ Date getCreateTime(); + /** + * The ID of the batch associated with this job. null if no batch is associated with this job. + * The following jobs are associated with batches: + *
    + *
  • Seed Jobs
  • + *
  • Monitor Jobs
  • + *
  • Batch Execution Jobs
  • + *
+ * @return The ID of the batch associated to the Job. + */ + String getBatchId(); } diff --git a/engine/src/main/java/org/operaton/bpm/engine/runtime/ModificationBuilder.java b/engine/src/main/java/org/operaton/bpm/engine/runtime/ModificationBuilder.java index aecb21f13ce..45714e63aa2 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/runtime/ModificationBuilder.java +++ b/engine/src/main/java/org/operaton/bpm/engine/runtime/ModificationBuilder.java @@ -24,6 +24,7 @@ import org.operaton.bpm.engine.authorization.Permissions; import org.operaton.bpm.engine.authorization.Resources; import org.operaton.bpm.engine.batch.Batch; +import org.operaton.bpm.engine.history.HistoricProcessInstanceQuery; public interface ModificationBuilder extends InstantiationBuilder{ @@ -116,5 +117,12 @@ public interface ModificationBuilder extends InstantiationBuilder */ Batch executeAsync(); + + /** + * @param historicProcessInstanceQuery a query which selects the process instances to modify. + * It is advised to include the `unfinished` filter in the historicProcessInstanceQuery as finished instances cause failures for the modification. + * Query results are restricted to process instances for which the user has {@link Permissions#READ_HISTORY} permission. + */ + ModificationBuilder historicProcessInstanceQuery(HistoricProcessInstanceQuery historicProcessInstanceQuery); } diff --git a/engine/src/main/java/org/operaton/bpm/engine/task/Task.java b/engine/src/main/java/org/operaton/bpm/engine/task/Task.java index 34cb43536e9..8dfad21c148 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/task/Task.java +++ b/engine/src/main/java/org/operaton/bpm/engine/task/Task.java @@ -202,4 +202,9 @@ public interface Task { * @param taskState the taskState to set */ void setTaskState(String taskState); + /** Returns if an attachment exists for the task */ + boolean hasAttachment(); + /** Signifies if a comment exists for the task */ + boolean hasComment(); + } diff --git a/engine/src/main/java/org/operaton/bpm/engine/task/TaskQuery.java b/engine/src/main/java/org/operaton/bpm/engine/task/TaskQuery.java index b995b5e0ccd..95157942102 100644 --- a/engine/src/main/java/org/operaton/bpm/engine/task/TaskQuery.java +++ b/engine/src/main/java/org/operaton/bpm/engine/task/TaskQuery.java @@ -314,6 +314,25 @@ public interface TaskQuery extends Query { */ TaskQuery taskCandidateGroupExpression(String candidateGroupExpression); + /** + * Only select tasks whose candidate users belong to groups matching the given parameter. + * The syntax is that of SQL: for example usage: nameLike(%operaton%) + * + *

+ * Per default it only selects tasks which are not already assigned + * to a user. To also include assigned task in the result specify + * {@link #includeAssignedTasks()} in your query. + *

+ * + * @throws ProcessEngineException
  • When query is executed and {@link #taskCandidateUser(String)} or + * {@link #taskCandidateUserExpression(String)} (List)} has been executed on the + * "and query" instance.
    + * No exception is thrown when query is executed and {@link #taskCandidateUser(String)} or + * {@link #taskCandidateUserExpression(String)} has been executed on the "or query" instance.
  • + *
  • When passed group is null.
+ */ + TaskQuery taskCandidateGroupLike(String candidateGroupLike); + /** * Only select tasks for which the 'candidateGroup' is one of the given groups. * @@ -1104,4 +1123,11 @@ public interface TaskQuery extends Query { * this exception, {@link #or()} must be invoked first. */ TaskQuery endOr(); + + /** + * Evaluates existence of attachment and comments associated with the task, defaults to false. + * Adding the filter will do additional attachment and comments queries to the database, + * it might slow down the query in case of tables having high volume of data. + */ + TaskQuery withCommentAttachmentInfo(); } diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.db2.create.engine.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.db2.create.engine.sql index b3989a1857c..c007171ede6 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.db2.create.engine.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.db2.create.engine.sql @@ -130,6 +130,7 @@ create table ACT_RU_JOB ( TENANT_ID_ varchar(64), CREATE_TIME_ timestamp, LAST_FAILURE_LOG_ID_ varchar(64), + BATCH_ID_ varchar(64), primary key (ID_) ); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.db2.create.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.db2.create.history.sql index f4008b1d6ef..29445d439dc 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.db2.create.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.db2.create.history.sql @@ -35,6 +35,7 @@ create table ACT_HI_PROCINST ( DELETE_REASON_ varchar(4000), TENANT_ID_ varchar(64), STATE_ varchar(255), + RESTARTED_PROC_INST_ID_ varchar(64), primary key (ID_) ); @@ -288,6 +289,7 @@ create table ACT_HI_JOB_LOG ( TENANT_ID_ varchar(64), HOSTNAME_ varchar(255), REMOVAL_TIME_ timestamp, + BATCH_ID_ varchar(64), primary key (ID_) ); @@ -340,6 +342,7 @@ create index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST(START_TIME_, END_T create index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST(PROC_DEF_ID_, END_TIME_); create index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST(REMOVAL_TIME_); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); create index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST(START_TIME_, END_TIME_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.h2.create.engine.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.h2.create.engine.sql index 7c7c64ea59a..1af710fbdfc 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.h2.create.engine.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.h2.create.engine.sql @@ -130,6 +130,7 @@ create table ACT_RU_JOB ( TENANT_ID_ varchar(64), CREATE_TIME_ timestamp, LAST_FAILURE_LOG_ID_ varchar(64), + BATCH_ID_ varchar(64), primary key (ID_) ); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.h2.create.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.h2.create.history.sql index 52a04fde94c..1edf441710d 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.h2.create.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.h2.create.history.sql @@ -35,6 +35,7 @@ create table ACT_HI_PROCINST ( DELETE_REASON_ varchar(4000), TENANT_ID_ varchar(64), STATE_ varchar(255), + RESTARTED_PROC_INST_ID_ varchar(64), primary key (ID_), unique (PROC_INST_ID_) ); @@ -287,6 +288,7 @@ create table ACT_HI_JOB_LOG ( TENANT_ID_ varchar(64), HOSTNAME_ varchar(255), REMOVAL_TIME_ timestamp, + BATCH_ID_ varchar(64), primary key (ID_) ); @@ -339,6 +341,7 @@ create index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST(START_TIME_, END_T create index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST(PROC_DEF_ID_, END_TIME_); create index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST(REMOVAL_TIME_); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); create index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST(START_TIME_, END_TIME_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mariadb.create.engine.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mariadb.create.engine.sql index 522ae0e1c5a..f24ca14d222 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mariadb.create.engine.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mariadb.create.engine.sql @@ -130,6 +130,7 @@ create table ACT_RU_JOB ( TENANT_ID_ varchar(64), CREATE_TIME_ datetime(3), LAST_FAILURE_LOG_ID_ varchar(64), + BATCH_ID_ varchar(64), primary key (ID_) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mariadb.create.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mariadb.create.history.sql index 01a1cc72d12..228b264ff75 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mariadb.create.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mariadb.create.history.sql @@ -35,6 +35,7 @@ create table ACT_HI_PROCINST ( DELETE_REASON_ varchar(4000), TENANT_ID_ varchar(64), STATE_ varchar(255), + RESTARTED_PROC_INST_ID_ varchar(64), primary key (ID_), unique (PROC_INST_ID_) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin; @@ -287,6 +288,7 @@ create table ACT_HI_JOB_LOG ( TENANT_ID_ varchar(64), HOSTNAME_ varchar(255), REMOVAL_TIME_ datetime(3), + BATCH_ID_ varchar(64), primary key (ID_) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin; @@ -339,6 +341,7 @@ create index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST(START_TIME_, END_T create index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST(PROC_DEF_ID_, END_TIME_); create index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST(REMOVAL_TIME_); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); create index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST(START_TIME_, END_TIME_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mssql.create.engine.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mssql.create.engine.sql index f214c3a2547..4a2abbe0a20 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mssql.create.engine.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mssql.create.engine.sql @@ -130,6 +130,7 @@ create table ACT_RU_JOB ( TENANT_ID_ nvarchar(64), CREATE_TIME_ datetime2, LAST_FAILURE_LOG_ID_ nvarchar(64), + BATCH_ID_ nvarchar(64), primary key (ID_) ); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mssql.create.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mssql.create.history.sql index d6b3f9a6d06..076516d4c12 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mssql.create.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mssql.create.history.sql @@ -35,6 +35,7 @@ create table ACT_HI_PROCINST ( DELETE_REASON_ nvarchar(4000), TENANT_ID_ nvarchar(64), STATE_ nvarchar(255), + RESTARTED_PROC_INST_ID_ nvarchar(64), primary key (ID_), unique (PROC_INST_ID_) ); @@ -286,6 +287,7 @@ create table ACT_HI_JOB_LOG ( TENANT_ID_ nvarchar(64), HOSTNAME_ nvarchar(255), REMOVAL_TIME_ datetime2, + BATCH_ID_ nvarchar(64), primary key (ID_) ); @@ -338,6 +340,7 @@ create index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST(START_TIME_, END_T create index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST(PROC_DEF_ID_, END_TIME_); create index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST(REMOVAL_TIME_); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); create index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST(START_TIME_, END_TIME_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mysql.create.engine.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mysql.create.engine.sql index 49a5962aea2..4d60e888494 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mysql.create.engine.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mysql.create.engine.sql @@ -130,6 +130,7 @@ create table ACT_RU_JOB ( TENANT_ID_ varchar(64), CREATE_TIME_ datetime, LAST_FAILURE_LOG_ID_ varchar(64), + BATCH_ID_ varchar(64), primary key (ID_) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mysql.create.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mysql.create.history.sql index 478f30ea48a..4559ad612b8 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mysql.create.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.mysql.create.history.sql @@ -35,6 +35,7 @@ create table ACT_HI_PROCINST ( DELETE_REASON_ varchar(4000), TENANT_ID_ varchar(64), STATE_ varchar(255), + RESTARTED_PROC_INST_ID_ varchar(64), primary key (ID_), unique (PROC_INST_ID_) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin; @@ -287,6 +288,7 @@ create table ACT_HI_JOB_LOG ( TENANT_ID_ varchar(64), HOSTNAME_ varchar(255), REMOVAL_TIME_ datetime, + BATCH_ID_ varchar(64), primary key (ID_) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin; @@ -340,6 +342,7 @@ create index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST(START_TIME_, END_T create index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST(PROC_DEF_ID_, END_TIME_); create index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST(REMOVAL_TIME_); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); create index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST(START_TIME_, END_TIME_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.oracle.create.engine.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.oracle.create.engine.sql index 05a6fddf78a..814e48459d3 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.oracle.create.engine.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.oracle.create.engine.sql @@ -130,6 +130,7 @@ create table ACT_RU_JOB ( TENANT_ID_ NVARCHAR2(64), CREATE_TIME_ TIMESTAMP(6), LAST_FAILURE_LOG_ID_ NVARCHAR2(64), + BATCH_ID_ NVARCHAR2(64), primary key (ID_) ); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.oracle.create.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.oracle.create.history.sql index 430ed1ee56d..e28095b8416 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.oracle.create.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.oracle.create.history.sql @@ -35,6 +35,7 @@ create table ACT_HI_PROCINST ( DELETE_REASON_ NVARCHAR2(2000), TENANT_ID_ NVARCHAR2(64), STATE_ NVARCHAR2(255), + RESTARTED_PROC_INST_ID_ NVARCHAR2(64), primary key (ID_), unique (PROC_INST_ID_) ); @@ -287,6 +288,7 @@ create table ACT_HI_JOB_LOG ( TENANT_ID_ NVARCHAR2(64), HOSTNAME_ NVARCHAR2(255), REMOVAL_TIME_ TIMESTAMP(6), + BATCH_ID_ NVARCHAR2(64), primary key (ID_) ); @@ -339,6 +341,7 @@ create index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST(START_TIME_, END_T create index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST(PROC_DEF_ID_, END_TIME_); create index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST(REMOVAL_TIME_); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); create index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST(START_TIME_, END_TIME_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.postgres.create.engine.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.postgres.create.engine.sql index e05f02d7214..e45f8533f0f 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.postgres.create.engine.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.postgres.create.engine.sql @@ -130,6 +130,7 @@ create table ACT_RU_JOB ( TENANT_ID_ varchar(64), CREATE_TIME_ timestamp, LAST_FAILURE_LOG_ID_ varchar(64), + BATCH_ID_ varchar(64), primary key (ID_) ); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.postgres.create.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.postgres.create.history.sql index 2126975e74a..c95743b5187 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.postgres.create.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/create/activiti.postgres.create.history.sql @@ -35,6 +35,7 @@ create table ACT_HI_PROCINST ( DELETE_REASON_ varchar(4000), TENANT_ID_ varchar(64), STATE_ varchar(255), + RESTARTED_PROC_INST_ID_ varchar(64), primary key (ID_), unique (PROC_INST_ID_) ); @@ -287,6 +288,7 @@ create table ACT_HI_JOB_LOG ( TENANT_ID_ varchar(64), HOSTNAME_ varchar(255), REMOVAL_TIME_ timestamp, + BATCH_ID_ varchar(64), primary key (ID_) ); @@ -339,6 +341,7 @@ create index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST(START_TIME_, END_T create index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST(PROC_DEF_ID_, END_TIME_); create index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST(REMOVAL_TIME_); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); create index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST(ROOT_PROC_INST_ID_); create index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST(START_TIME_, END_TIME_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.db2.drop.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.db2.drop.history.sql index bdd56029478..9d8be4d3f31 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.db2.drop.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.db2.drop.history.sql @@ -23,6 +23,7 @@ drop index ACT_IDX_HI_PRO_INST_PROC_TIME; drop index ACT_IDX_HI_PI_PDEFID_END_TIME; drop index ACT_IDX_HI_PRO_INST_ROOT_PI; drop index ACT_IDX_HI_PRO_INST_RM_TIME; +drop index ACT_IDX_HI_PRO_RST_PRO_INST_ID; drop index ACT_IDX_HI_ACTINST_ROOT_PI; drop index ACT_IDX_HI_ACT_INST_START_END; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.h2.drop.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.h2.drop.history.sql index 8bf4e2a4655..bc856ed8645 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.h2.drop.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.h2.drop.history.sql @@ -23,6 +23,7 @@ drop index ACT_IDX_HI_PRO_INST_PROC_TIME; drop index ACT_IDX_HI_PI_PDEFID_END_TIME; drop index ACT_IDX_HI_PRO_INST_ROOT_PI; drop index ACT_IDX_HI_PRO_INST_RM_TIME; +drop index ACT_IDX_HI_PRO_RST_PRO_INST_ID; drop index ACT_IDX_HI_ACTINST_ROOT_PI; drop index ACT_IDX_HI_ACT_INST_START_END; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mariadb.drop.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mariadb.drop.history.sql index 2fff71cc558..0cebb8ea81f 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mariadb.drop.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mariadb.drop.history.sql @@ -23,6 +23,7 @@ drop index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST; drop index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST; drop index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST; drop index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST; +drop index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST; drop index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST; drop index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mssql.drop.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mssql.drop.history.sql index 3cbce879033..de4b0ab35b7 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mssql.drop.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mssql.drop.history.sql @@ -23,6 +23,7 @@ drop index ACT_HI_PROCINST.ACT_IDX_HI_PRO_INST_PROC_TIME; drop index ACT_HI_PROCINST.ACT_IDX_HI_PI_PDEFID_END_TIME; drop index ACT_HI_PROCINST.ACT_IDX_HI_PRO_INST_ROOT_PI; drop index ACT_HI_PROCINST.ACT_IDX_HI_PRO_INST_RM_TIME; +drop index ACT_HI_PROCINST.ACT_IDX_HI_PRO_RST_PRO_INST_ID; drop index ACT_HI_ACTINST.ACT_IDX_HI_ACTINST_ROOT_PI; drop index ACT_HI_ACTINST.ACT_IDX_HI_ACT_INST_START_END; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mysql.drop.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mysql.drop.history.sql index cc7fae60ffd..e63914408cb 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mysql.drop.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.mysql.drop.history.sql @@ -23,6 +23,7 @@ drop index ACT_IDX_HI_PRO_INST_PROC_TIME on ACT_HI_PROCINST; drop index ACT_IDX_HI_PI_PDEFID_END_TIME on ACT_HI_PROCINST; drop index ACT_IDX_HI_PRO_INST_ROOT_PI on ACT_HI_PROCINST; drop index ACT_IDX_HI_PRO_INST_RM_TIME on ACT_HI_PROCINST; +drop index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST; drop index ACT_IDX_HI_ACTINST_ROOT_PI on ACT_HI_ACTINST; drop index ACT_IDX_HI_ACT_INST_START_END on ACT_HI_ACTINST; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.oracle.drop.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.oracle.drop.history.sql index b7318b2807f..e6acb942fd6 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.oracle.drop.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.oracle.drop.history.sql @@ -23,6 +23,7 @@ drop index ACT_IDX_HI_PRO_INST_PROC_TIME; drop index ACT_IDX_HI_PI_PDEFID_END_TIME; drop index ACT_IDX_HI_PRO_INST_ROOT_PI; drop index ACT_IDX_HI_PRO_INST_RM_TIME; +drop index ACT_IDX_HI_PRO_RST_PRO_INST_ID; drop index ACT_IDX_HI_ACTINST_ROOT_PI; drop index ACT_IDX_HI_ACT_INST_START_END; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.postgres.drop.history.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.postgres.drop.history.sql index 5f9c798074d..bb0e521ff91 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.postgres.drop.history.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/drop/activiti.postgres.drop.history.sql @@ -23,6 +23,7 @@ drop index ACT_IDX_HI_PRO_INST_PROC_TIME; drop index ACT_IDX_HI_PI_PDEFID_END_TIME; drop index ACT_IDX_HI_PRO_INST_ROOT_PI; drop index ACT_IDX_HI_PRO_INST_RM_TIME; +drop index ACT_IDX_HI_PRO_RST_PRO_INST_ID; drop index ACT_IDX_HI_ACTINST_ROOT_PI; drop index ACT_IDX_HI_ACT_INST_START_END; diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/db2_engine_7.21_to_7.22.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/db2_engine_7.21_to_7.22.sql index 7a8ada55ac2..55583c6f431 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/db2_engine_7.21_to_7.22.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/db2_engine_7.21_to_7.22.sql @@ -21,3 +21,9 @@ values ('1100', CURRENT_TIMESTAMP, '7.22.0'); alter table ACT_RU_TASK add column TASK_STATE_ varchar(64); alter table ACT_HI_TASKINST add column TASK_STATE_ varchar(64); + +alter table ACT_RU_JOB add column BATCH_ID_ varchar(64); +alter table ACT_HI_JOB_LOG add column BATCH_ID_ varchar(64); + +alter table ACT_HI_PROCINST add RESTARTED_PROC_INST_ID_ varchar(64); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/h2_engine_7.21_to_7.22.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/h2_engine_7.21_to_7.22.sql index 7a8ada55ac2..55583c6f431 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/h2_engine_7.21_to_7.22.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/h2_engine_7.21_to_7.22.sql @@ -21,3 +21,9 @@ values ('1100', CURRENT_TIMESTAMP, '7.22.0'); alter table ACT_RU_TASK add column TASK_STATE_ varchar(64); alter table ACT_HI_TASKINST add column TASK_STATE_ varchar(64); + +alter table ACT_RU_JOB add column BATCH_ID_ varchar(64); +alter table ACT_HI_JOB_LOG add column BATCH_ID_ varchar(64); + +alter table ACT_HI_PROCINST add RESTARTED_PROC_INST_ID_ varchar(64); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mariadb_engine_7.21_to_7.22.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mariadb_engine_7.21_to_7.22.sql index 7a8ada55ac2..55583c6f431 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mariadb_engine_7.21_to_7.22.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mariadb_engine_7.21_to_7.22.sql @@ -21,3 +21,9 @@ values ('1100', CURRENT_TIMESTAMP, '7.22.0'); alter table ACT_RU_TASK add column TASK_STATE_ varchar(64); alter table ACT_HI_TASKINST add column TASK_STATE_ varchar(64); + +alter table ACT_RU_JOB add column BATCH_ID_ varchar(64); +alter table ACT_HI_JOB_LOG add column BATCH_ID_ varchar(64); + +alter table ACT_HI_PROCINST add RESTARTED_PROC_INST_ID_ varchar(64); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mssql_engine_7.21_to_7.22.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mssql_engine_7.21_to_7.22.sql index 5c49433ff26..66ea5d03d6d 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mssql_engine_7.21_to_7.22.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mssql_engine_7.21_to_7.22.sql @@ -21,3 +21,9 @@ values ('1100', CURRENT_TIMESTAMP, '7.22.0'); alter table ACT_RU_TASK add TASK_STATE_ nvarchar(64); alter table ACT_HI_TASKINST add TASK_STATE_ nvarchar(64); + +alter table ACT_RU_JOB add BATCH_ID_ nvarchar(64); +alter table ACT_HI_JOB_LOG add BATCH_ID_ nvarchar(64); + +alter table ACT_HI_PROCINST add RESTARTED_PROC_INST_ID_ nvarchar(64); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mysql_engine_7.21_to_7.22.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mysql_engine_7.21_to_7.22.sql index 7a8ada55ac2..55583c6f431 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mysql_engine_7.21_to_7.22.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/mysql_engine_7.21_to_7.22.sql @@ -21,3 +21,9 @@ values ('1100', CURRENT_TIMESTAMP, '7.22.0'); alter table ACT_RU_TASK add column TASK_STATE_ varchar(64); alter table ACT_HI_TASKINST add column TASK_STATE_ varchar(64); + +alter table ACT_RU_JOB add column BATCH_ID_ varchar(64); +alter table ACT_HI_JOB_LOG add column BATCH_ID_ varchar(64); + +alter table ACT_HI_PROCINST add RESTARTED_PROC_INST_ID_ varchar(64); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/oracle_engine_7.21_to_7.22.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/oracle_engine_7.21_to_7.22.sql index 1136a2087ef..afe6e9d3f09 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/oracle_engine_7.21_to_7.22.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/oracle_engine_7.21_to_7.22.sql @@ -21,3 +21,9 @@ values ('1100', CURRENT_TIMESTAMP, '7.22.0'); alter table ACT_RU_TASK add TASK_STATE_ NVARCHAR2(64); alter table ACT_HI_TASKINST add TASK_STATE_ NVARCHAR2(64); + +alter table ACT_RU_JOB add BATCH_ID_ NVARCHAR2(64); +alter table ACT_HI_JOB_LOG add BATCH_ID_ NVARCHAR2(64); + +alter table ACT_HI_PROCINST add RESTARTED_PROC_INST_ID_ NVARCHAR2(64); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/postgres_engine_7.21_to_7.22.sql b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/postgres_engine_7.21_to_7.22.sql index 7a8ada55ac2..55583c6f431 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/postgres_engine_7.21_to_7.22.sql +++ b/engine/src/main/resources/org/operaton/bpm/engine/db/upgrade/postgres_engine_7.21_to_7.22.sql @@ -21,3 +21,9 @@ values ('1100', CURRENT_TIMESTAMP, '7.22.0'); alter table ACT_RU_TASK add column TASK_STATE_ varchar(64); alter table ACT_HI_TASKINST add column TASK_STATE_ varchar(64); + +alter table ACT_RU_JOB add column BATCH_ID_ varchar(64); +alter table ACT_HI_JOB_LOG add column BATCH_ID_ varchar(64); + +alter table ACT_HI_PROCINST add RESTARTED_PROC_INST_ID_ varchar(64); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); diff --git a/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Authorization.xml b/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Authorization.xml index 3b4f8b7e12b..70bca14a0ef 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Authorization.xml +++ b/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Authorization.xml @@ -844,7 +844,8 @@ - + + @@ -861,6 +862,34 @@ OR A.GROUP_ID_ IN #{item} ) + + ) + + + + + left join + inner join + + ( + SELECT A.* + FROM ${prefix}ACT_RU_AUTHORIZATION A + WHERE A.TYPE_ < 2 + AND A.USER_ID_ in ( #{authCheck.authUserId, jdbcType=VARCHAR}, '*') + + + UNION ( + SELECT A.* + FROM ${prefix}ACT_RU_AUTHORIZATION A + WHERE A.TYPE_ < 2 + AND A.GROUP_ID_ IN #{item} + + ) + + ) + + + AND ( @@ -874,8 +903,7 @@ ) - - ) + @@ -550,6 +562,14 @@ ${queryType} INC.INCIDENT_TYPE_ = #{query.incidentType} + + + ${queryType} INC.ID_ IN + + #{incidentId} + + + ${queryType} INC.INCIDENT_MSG_ = #{query.incidentMessage} @@ -623,6 +643,21 @@ ) + + ${queryType} ( + ( + HAI.END_TIME_ IS NULL + AND HAI.ACT_ID_ IN + + #{activityId} + + ) OR INCACT.ACTIVITY_ID_ IN + + #{activityId} + + ) + + ${queryType} ( HAI.END_TIME_ IS NOT NULL diff --git a/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Job.xml b/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Job.xml index 49a924ac40b..f22101cdfb4 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Job.xml +++ b/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Job.xml @@ -137,6 +137,7 @@ + @@ -491,6 +492,7 @@ SEQUENCE_COUNTER_, TENANT_ID_, CREATE_TIME_, + BATCH_ID_, REV_ ) values (#{id, jdbcType=VARCHAR}, @@ -519,6 +521,7 @@ #{sequenceCounter, jdbcType=BIGINT}, #{tenantId, jdbcType=VARCHAR}, #{createTime, jdbcType=TIMESTAMP}, + #{batchId, jdbcType=VARCHAR}, 1 ) @@ -547,7 +550,8 @@ HANDLER_CFG_ = #{jobHandlerConfigurationRaw, jdbcType=VARCHAR}, PRIORITY_ = #{priority, jdbcType=BIGINT}, SEQUENCE_COUNTER_ = #{sequenceCounter, jdbcType=BIGINT}, - LAST_FAILURE_LOG_ID_ = #{lastFailureLogId, jdbcType=VARCHAR} + LAST_FAILURE_LOG_ID_ = #{lastFailureLogId, jdbcType=VARCHAR}, + BATCH_ID_ = #{batchId, jdbcType=VARCHAR} where ID_= #{id, jdbcType=VARCHAR} and REV_ = #{revision, jdbcType=INTEGER} @@ -602,6 +606,7 @@ SEQUENCE_COUNTER_, TENANT_ID_, CREATE_TIME_, + BATCH_ID_, REV_ ) values (#{id, jdbcType=VARCHAR}, @@ -628,6 +633,7 @@ #{sequenceCounter, jdbcType=BIGINT}, #{tenantId, jdbcType=VARCHAR}, #{createTime, jdbcType=TIMESTAMP}, + #{batchId, jdbcType=VARCHAR}, 1 ) @@ -653,7 +659,8 @@ HANDLER_CFG_ = #{jobHandlerConfigurationRaw, jdbcType=VARCHAR}, PRIORITY_ = #{priority, jdbcType=BIGINT}, SEQUENCE_COUNTER_ = #{sequenceCounter, jdbcType=BIGINT}, - LAST_FAILURE_LOG_ID_ = #{lastFailureLogId, jdbcType=VARCHAR} + LAST_FAILURE_LOG_ID_ = #{lastFailureLogId, jdbcType=VARCHAR}, + BATCH_ID_ = #{batchId, jdbcType=VARCHAR} where ID_= #{id, jdbcType=VARCHAR} and REV_ = #{revision, jdbcType=INTEGER} @@ -685,6 +692,7 @@ SEQUENCE_COUNTER_, TENANT_ID_, CREATE_TIME_, + BATCH_ID_, REV_ ) values (#{id, jdbcType=VARCHAR}, @@ -711,6 +719,7 @@ #{sequenceCounter, jdbcType=BIGINT}, #{tenantId, jdbcType=VARCHAR}, #{createTime, jdbcType=TIMESTAMP}, + #{batchId, jdbcType=VARCHAR}, 1 ) @@ -736,7 +745,8 @@ HANDLER_CFG_ = #{jobHandlerConfigurationRaw, jdbcType=VARCHAR}, PRIORITY_ = #{priority, jdbcType=BIGINT}, SEQUENCE_COUNTER_ = #{sequenceCounter, jdbcType=BIGINT}, - LAST_FAILURE_LOG_ID_ = #{lastFailureLogId, jdbcType=VARCHAR} + LAST_FAILURE_LOG_ID_ = #{lastFailureLogId, jdbcType=VARCHAR}, + BATCH_ID_ = #{batchId, jdbcType=VARCHAR} where ID_= #{id, jdbcType=VARCHAR} and REV_ = #{revision, jdbcType=INTEGER} diff --git a/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Task.xml b/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Task.xml index 7404a44f6ec..c9663e659ff 100644 --- a/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Task.xml +++ b/engine/src/main/resources/org/operaton/bpm/engine/impl/mapping/entity/Task.xml @@ -250,7 +250,7 @@ - + + + or + + + I.GROUP_ID_ LIKE #{candidateGroupLike} + ) diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/api/authorization/externaltask/ExternalTaskQueryAuthorizationTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/api/authorization/externaltask/ExternalTaskQueryAuthorizationTest.java index 57986b731f5..77ad1667985 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/api/authorization/externaltask/ExternalTaskQueryAuthorizationTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/api/authorization/externaltask/ExternalTaskQueryAuthorizationTest.java @@ -16,16 +16,22 @@ */ package org.operaton.bpm.engine.test.api.authorization.externaltask; +import static org.assertj.core.api.Assertions.assertThat; import static org.operaton.bpm.engine.authorization.Authorization.ANY; +import static org.operaton.bpm.engine.authorization.Permissions.ALL; import static org.operaton.bpm.engine.authorization.Permissions.READ; import static org.operaton.bpm.engine.authorization.Permissions.READ_INSTANCE; import static org.operaton.bpm.engine.authorization.Resources.PROCESS_DEFINITION; import static org.operaton.bpm.engine.authorization.Resources.PROCESS_INSTANCE; import static org.junit.Assert.assertEquals; +import java.util.List; import org.operaton.bpm.engine.externaltask.ExternalTaskQuery; +import org.operaton.bpm.engine.externaltask.LockedExternalTask; import org.operaton.bpm.engine.test.api.authorization.AuthorizationTest; +import org.operaton.commons.testing.ProcessEngineLoggingRule; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; /** @@ -34,10 +40,15 @@ */ public class ExternalTaskQueryAuthorizationTest extends AuthorizationTest { + protected static final String WORKER_ID = "aWorkerId"; + protected static final String EXTERNAL_TASK_TOPIC = "externalTaskTopic"; protected String deploymentId; protected String instance1Id; protected String instance2Id; + @Rule + public ProcessEngineLoggingRule loggingRule = new ProcessEngineLoggingRule(); + @Override @Before public void setUp() throws Exception { @@ -135,4 +146,52 @@ public void shouldNotFindTaskWithRevokedReadOnProcessInstance() { // then verifyQueryResults(query, 1); } + + @Test + public void shouldFetchAndLockWhenUserAuthorized() { + // given + createGrantAuthorization(PROCESS_DEFINITION, ANY, userId, ALL); + + // when + List externalTasks = externalTaskService + .fetchAndLock(1, WORKER_ID) + .topic(EXTERNAL_TASK_TOPIC, 10) + .execute(); + + // then + assertThat(externalTasks).hasSize(1); + assertThat(externalTasks).extracting(LockedExternalTask::getTopicName).first().isEqualTo(EXTERNAL_TASK_TOPIC); + } + + @Test + public void shouldFetchAndLockWhenGroupAuthorized() { + // given + createGrantAuthorizationGroup(PROCESS_DEFINITION, ANY, groupId, ALL); + + // when + List externalTasks = externalTaskService + .fetchAndLock(1, WORKER_ID) + .topic(EXTERNAL_TASK_TOPIC, 10) + .execute(); + + // then + assertThat(externalTasks).hasSize(1); + assertThat(externalTasks).extracting(LockedExternalTask::getTopicName).first().isEqualTo(EXTERNAL_TASK_TOPIC); + } + + @Test + public void shouldNotFetchAndLockWhenUnauthorized() { + // given + createGrantAuthorization(PROCESS_DEFINITION, ANY, userId, READ_INSTANCE); + createGrantAuthorizationGroup(PROCESS_DEFINITION, ANY, groupId, READ_INSTANCE); + + // when + List externalTasks = externalTaskService + .fetchAndLock(1, WORKER_ID) + .topic(EXTERNAL_TASK_TOPIC, 10) + .execute(); + + // then + assertThat(externalTasks).isEmpty(); + } } diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/api/filter/FilterTaskQueryTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/api/filter/FilterTaskQueryTest.java index 4d752a026a4..d9b2dacaa69 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/api/filter/FilterTaskQueryTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/api/filter/FilterTaskQueryTest.java @@ -185,6 +185,7 @@ public void testTaskQuery() { query.taskUnassigned(); query.taskAssigned(); query.taskDelegationState(testDelegationState); + query.taskCandidateGroupLike(testString); query.taskCandidateGroupIn(testCandidateGroups); query.taskCandidateGroupInExpression(testString); query.withCandidateGroups(); @@ -290,6 +291,7 @@ public void testTaskQuery() { assertTrue(query.isUnassigned()); assertTrue(query.isAssigned()); assertEquals(testDelegationState, query.getDelegationState()); + assertEquals(testString, query.getCandidateGroupLike()); assertEquals(testCandidateGroups, query.getCandidateGroups()); assertTrue(query.isWithCandidateGroups()); assertTrue(query.isWithoutCandidateGroups()); @@ -657,6 +659,21 @@ public void testTaskQueryCandidateGroup() { assertEquals(testGroup.getId(), query.getExpressions().get("taskCandidateGroup")); } + @Test + public void testTaskQueryCandidateGroupLike() { + // given + TaskQueryImpl query = new TaskQueryImpl(); + query.taskCandidateGroupLike(testGroup.getId()); + + saveQuery(query); + + // when + query = filter.getQuery(); + + // then + assertEquals(testGroup.getId(), query.getCandidateGroupLike()); + } + @Test public void testTaskQueryCandidateUserIncludeAssignedTasks() { TaskQueryImpl query = new TaskQueryImpl(); @@ -709,6 +726,23 @@ public void testTaskQueryCandidateGroupExpressionIncludeAssignedTasks() { assertTrue(query.isIncludeAssignedTasks()); } + @Test + public void testTaskQueryCandidateGroupLikeIncludeAssignedTasks() { + // given + TaskQueryImpl query = new TaskQueryImpl(); + query.taskCandidateGroupLike(testGroup.getId()); + query.includeAssignedTasks(); + + saveQuery(query); + + // when + query = filter.getQuery(); + + // then + assertEquals(testGroup.getId(), query.getCandidateGroupLike()); + assertTrue(query.isIncludeAssignedTasks()); + } + @Test public void testTaskQueryCandidateGroupsIncludeAssignedTasks() { TaskQueryImpl query = new TaskQueryImpl(); @@ -823,6 +857,56 @@ public void testExtendingTaskQueryWithAssigneeNotIn() { assertEquals(0, extendingQueryTasks.size()); } + @Test + public void testExtendingEmptyTaskQueryWithCandidateGroupLike() { + // given 3 test tasks created during setup + TaskQuery query = taskService.createTaskQuery(); + saveQuery(query); + List tasks = filterService.list(filter.getId()); + assertEquals(3, tasks.size()); + + // when extending the query with a "candidate group like" + TaskQuery extendingQuery = taskService.createTaskQuery(); + extendingQuery.taskCandidateGroupLike("%count%"); + + // then there is 1 unassigned task with the candidate group "accounting" + tasks = filterService.list(filter.getId(), extendingQuery); + assertEquals(1, tasks.size()); + } + + @Test + public void testExtendingCandidateGroupLikeTaskQueryWithEmpty() { + // given 3 existing tasks but only 1 unassigned task that matches the initial filter + TaskQuery query = taskService.createTaskQuery().taskCandidateGroupLike("%count%"); + saveQuery(query); + List tasks = filterService.list(filter.getId()); + assertEquals(1, tasks.size()); + + // when extending the query with an empty query + TaskQuery extendingQuery = taskService.createTaskQuery(); + + // then the empty query should be ignored in favor of the existing value for "candidate group like" + tasks = filterService.list(filter.getId(), extendingQuery); + assertEquals(1, tasks.size()); + } + + @Test + public void testExtendingCandidateGroupLikeTaskQueryWithCandidateGroupLike() { + // given 3 existing tasks but zero match the initial filter + TaskQuery query = taskService.createTaskQuery().taskCandidateGroupLike("HR"); + saveQuery(query); + List tasks = filterService.list(filter.getId()); + assertTrue(tasks.isEmpty()); + + // when extending the query with a "candidate groups like" query + TaskQuery extendingQuery = taskService.createTaskQuery(); + extendingQuery.taskCandidateGroupLike("acc%"); + + // then the query should be return result of task matching the new filter + tasks = filterService.list(filter.getId(), extendingQuery); + assertEquals(1, tasks.size()); + } + @Test public void testExtendingTaskQueryListWithCandidateGroups() { TaskQuery query = taskService.createTaskQuery(); diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/ModificationExecutionAsyncTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/ModificationExecutionAsyncTest.java index dab148b01a7..3e9cc63d282 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/ModificationExecutionAsyncTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/ModificationExecutionAsyncTest.java @@ -35,12 +35,15 @@ import java.util.List; import org.assertj.core.api.Assertions; +import org.operaton.bpm.engine.HistoryService; import org.operaton.bpm.engine.ProcessEngineConfiguration; import org.operaton.bpm.engine.ProcessEngineException; import org.operaton.bpm.engine.RuntimeService; +import org.operaton.bpm.engine.TaskService; import org.operaton.bpm.engine.batch.Batch; import org.operaton.bpm.engine.batch.history.HistoricBatch; import org.operaton.bpm.engine.delegate.ExecutionListener; +import org.operaton.bpm.engine.history.HistoricProcessInstanceQuery; import org.operaton.bpm.engine.impl.batch.BatchSeedJobHandler; import org.operaton.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.operaton.bpm.engine.impl.persistence.entity.ExecutionEntity; @@ -55,6 +58,7 @@ import org.operaton.bpm.engine.runtime.ProcessInstanceQuery; import org.operaton.bpm.engine.runtime.VariableInstance; import org.operaton.bpm.engine.task.Task; +import org.operaton.bpm.engine.test.Deployment; import org.operaton.bpm.engine.test.ProcessEngineRule; import org.operaton.bpm.engine.test.RequiredHistoryLevel; import org.operaton.bpm.engine.test.bpmn.multiinstance.DelegateEvent; @@ -86,6 +90,7 @@ public class ModificationExecutionAsyncTest { protected ProcessEngineConfigurationImpl configuration; protected RuntimeService runtimeService; + protected HistoryService historyService; protected BpmnModelInstance instance; @@ -110,6 +115,7 @@ public static Collection scenarios() throws ParseException { @Before public void initServices() { runtimeService = rule.getRuntimeService(); + historyService = rule.getHistoryService(); } @Before @@ -245,6 +251,17 @@ public void testNullProcessInstanceQueryAsync() { } } + @Test + public void testNullHistoricProcessInstanceQueryAsync() { + + try { + runtimeService.createModification("processDefinitionId").startAfterActivity("user1").historicProcessInstanceQuery(null).executeAsync(); + fail("Should not succeed"); + } catch (ProcessEngineException e) { + assertThat(e.getMessage()).contains("Process instance ids is empty"); + } + } + @Test public void createModificationWithNonExistingProcessDefinitionId() { DeploymentWithDefinitions deployment = testRule.deploy(instance); @@ -841,6 +858,114 @@ public void testBatchExecutionFailureWithMissingProcessInstance() { assertThat(failedJob.getExceptionMessage()).contains("Process instance '" + deletedProcessInstanceId + "' cannot be modified"); } + @Test + public void testBatchExecutionFailureWithHistoricQueryThatMatchesDeletedInstance() { + DeploymentWithDefinitions deployment = testRule.deploy(instance); + ProcessDefinition processDefinition = deployment.getDeployedProcessDefinitions().get(0); + + List startedInstances = helper.startInstances("process1", 3); + RuntimeService runtimeService = rule.getRuntimeService(); + + String deletedProcessInstanceId = startedInstances.get(0); + + runtimeService.deleteProcessInstance(deletedProcessInstanceId, "test"); + + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().processDefinitionId(processDefinition.getId()); + + Batch batch = runtimeService + .createModification(processDefinition.getId()) + .startAfterActivity("user1") + .historicProcessInstanceQuery(historicProcessInstanceQuery) + .executeAsync(); + + helper.completeSeedJobs(batch); + + // when + helper.executeJobs(batch); + + // then the remaining process instance was modified + for (String processInstanceId : startedInstances) { + if (processInstanceId.equals(deletedProcessInstanceId)) { + ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId); + assertNull(updatedTree); + continue; + } + + ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId); + assertNotNull(updatedTree); + assertEquals(processInstanceId, updatedTree.getProcessInstanceId()); + + assertThat(updatedTree).hasStructure( + describeActivityInstanceTree( + processDefinition.getId()) + .activity("user1") + .activity("user2") + .done()); + } + + // and one batch job failed and has 2 retries left + List modificationJobs = helper.getExecutionJobs(batch); + assertEquals(1, modificationJobs.size()); + + Job failedJob = modificationJobs.get(0); + assertEquals(2, failedJob.getRetries()); + assertThat(failedJob.getExceptionMessage()).startsWith("ENGINE-13036"); + assertThat(failedJob.getExceptionMessage()).contains("Process instance '" + deletedProcessInstanceId + "' cannot be modified"); + } + + @Test + @Deployment(resources = { "org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.syncAfterOneTaskProcess.bpmn20.xml" }) + public void testBatchExecutionWithHistoricQueryUnfinished() { + // given + List startedInstances = helper.startInstances("oneTaskProcess", 3); + + TaskService taskService = rule.getTaskService(); + Task task = taskService.createTaskQuery().processInstanceId(startedInstances.get(0)).singleResult(); + String processDefinitionId = task.getProcessDefinitionId(); + String completedProcessInstanceId = task.getProcessInstanceId(); + assertNotNull(task); + taskService.complete(task.getId()); + + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().unfinished().processDefinitionId(processDefinitionId); + assertEquals(2, historicProcessInstanceQuery.count()); + + // then + Batch batch = runtimeService + .createModification(processDefinitionId) + .startAfterActivity("theStart") + .historicProcessInstanceQuery(historicProcessInstanceQuery) + .executeAsync(); + + helper.completeSeedJobs(batch); + + // when + helper.executeJobs(batch); + + // then the remaining process instance was modified + for (String processInstanceId : startedInstances) { + if (processInstanceId.equals(completedProcessInstanceId)) { + ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId); + assertNull(updatedTree); + continue; + } + + ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId); + assertNotNull(updatedTree); + assertEquals(processInstanceId, updatedTree.getProcessInstanceId()); + + assertThat(updatedTree).hasStructure( + describeActivityInstanceTree( + processDefinitionId) + .activity("theTask") + .activity("theTask") + .done()); + } + + // and one batch job failed and has 2 retries left + List modificationJobs = helper.getExecutionJobs(batch); + assertEquals(0, modificationJobs.size()); + } + @Test public void testBatchCreationWithProcessInstanceQuery() { int processInstanceCount = 15; @@ -862,6 +987,142 @@ public void testBatchCreationWithProcessInstanceQuery() { assertBatchCreated(batch, processInstanceCount); } + @Test + public void testBatchCreationWithHistoricProcessInstanceQuery() { + int processInstanceCount = 15; + DeploymentWithDefinitions deployment = testRule.deploy(instance); + ProcessDefinition processDefinition = deployment.getDeployedProcessDefinitions().get(0); + helper.startInstances("process1", 15); + + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().processDefinitionId(processDefinition.getId()); + assertEquals(processInstanceCount, historicProcessInstanceQuery.count()); + + // when + Batch batch = runtimeService + .createModification(processDefinition.getId()) + .startAfterActivity("user1") + .historicProcessInstanceQuery(historicProcessInstanceQuery) + .executeAsync(); + + // then a batch is created + assertBatchCreated(batch, processInstanceCount); + } + + @Test + @Deployment(resources = { "org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.syncAfterOneTaskProcess.bpmn20.xml" }) + public void testBatchExecutionFailureWithFinishedInstanceId() { + // given + List startedInstances = helper.startInstances("oneTaskProcess", 3); + + TaskService taskService = rule.getTaskService(); + Task task = taskService.createTaskQuery().processInstanceId(startedInstances.get(0)).singleResult(); + String processDefinitionId = task.getProcessDefinitionId(); + String completedProcessInstanceId = task.getProcessInstanceId(); + assertNotNull(task); + taskService.complete(task.getId()); + + // then + Batch batch = runtimeService + .createModification(processDefinitionId) + .startAfterActivity("theStart") + .processInstanceIds(startedInstances) + .executeAsync(); + + helper.completeSeedJobs(batch); + + // when + helper.executeJobs(batch); + + // then the remaining process instance was modified + for (String processInstanceId : startedInstances) { + if (processInstanceId.equals(completedProcessInstanceId)) { + ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId); + assertNull(updatedTree); + continue; + } + + ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId); + assertNotNull(updatedTree); + assertEquals(processInstanceId, updatedTree.getProcessInstanceId()); + + assertThat(updatedTree).hasStructure( + describeActivityInstanceTree( + processDefinitionId) + .activity("theTask") + .activity("theTask") + .done()); + } + + // and one batch job failed and has 2 retries left + List modificationJobs = helper.getExecutionJobs(batch); + assertEquals(1, modificationJobs.size()); + + Job failedJob = modificationJobs.get(0); + assertEquals(2, failedJob.getRetries()); + assertThat(failedJob.getExceptionMessage()).startsWith("ENGINE-13036"); + assertThat(failedJob.getExceptionMessage()).contains("Process instance '" + completedProcessInstanceId + "' cannot be modified"); + } + + + @Test + @Deployment(resources = { "org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.syncAfterOneTaskProcess.bpmn20.xml" }) + public void testBatchExecutionFailureWithHistoricQueryThatMatchesFinishedInstance() { + // given + List startedInstances = helper.startInstances("oneTaskProcess", 3); + + TaskService taskService = rule.getTaskService(); + Task task = taskService.createTaskQuery().processInstanceId(startedInstances.get(0)).singleResult(); + String processDefinitionId = task.getProcessDefinitionId(); + String completedProcessInstanceId = task.getProcessInstanceId(); + assertNotNull(task); + taskService.complete(task.getId()); + + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().processDefinitionId(processDefinitionId); + assertEquals(3, historicProcessInstanceQuery.count()); + + // then + Batch batch = runtimeService + .createModification(processDefinitionId) + .startAfterActivity("theStart") + .historicProcessInstanceQuery(historicProcessInstanceQuery) + .executeAsync(); + + helper.completeSeedJobs(batch); + + // when + helper.executeJobs(batch); + + // then the remaining process instance was modified + for (String processInstanceId : startedInstances) { + if (processInstanceId.equals(completedProcessInstanceId)) { + ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId); + assertNull(updatedTree); + continue; + } + + ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId); + assertNotNull(updatedTree); + assertEquals(processInstanceId, updatedTree.getProcessInstanceId()); + + assertThat(updatedTree).hasStructure( + describeActivityInstanceTree( + processDefinitionId) + .activity("theTask") + .activity("theTask") + .done()); + } + + // and one batch job failed and has 2 retries left + List modificationJobs = helper.getExecutionJobs(batch); + assertEquals(1, modificationJobs.size()); + + Job failedJob = modificationJobs.get(0); + assertEquals(2, failedJob.getRetries()); + assertThat(failedJob.getExceptionMessage()).startsWith("ENGINE-13036"); + assertThat(failedJob.getExceptionMessage()).contains("Process instance '" + completedProcessInstanceId + "' cannot be modified"); + } + + @Test public void testBatchCreationWithOverlappingProcessInstanceIdsAndQuery() { int processInstanceCount = 15; @@ -884,6 +1145,53 @@ public void testBatchCreationWithOverlappingProcessInstanceIdsAndQuery() { assertBatchCreated(batch, processInstanceCount); } + @Test + public void testBatchCreationWithOverlappingProcessInstanceIdsAndHistoricQuery() { + int processInstanceCount = 15; + DeploymentWithDefinitions deployment = testRule.deploy(instance); + ProcessDefinition processDefinition = deployment.getDeployedProcessDefinitions().get(0); + List processInstanceIds = helper.startInstances("process1", 15); + + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().processDefinitionId(processDefinition.getId()); + assertEquals(processInstanceCount, historicProcessInstanceQuery.count()); + + // when + Batch batch = runtimeService + .createModification(processDefinition.getId()) + .startTransition("seq") + .processInstanceIds(processInstanceIds) + .historicProcessInstanceQuery(historicProcessInstanceQuery) + .executeAsync(); + + // then a batch is created + assertBatchCreated(batch, processInstanceCount); + } + + @Test + public void testBatchCreationWithOverlappingHistoricQueryAndQuery() { + // given + int processInstanceCount = 15; + DeploymentWithDefinitions deployment = testRule.deploy(instance); + ProcessDefinition processDefinition = deployment.getDeployedProcessDefinitions().get(0); + helper.startInstances("process1", processInstanceCount); + + ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery().processDefinitionId(processDefinition.getId()); + assertEquals(processInstanceCount, processInstanceQuery.count()); + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().processDefinitionId(processDefinition.getId()); + assertEquals(processInstanceCount, historicProcessInstanceQuery.count()); + + // when + Batch batch = runtimeService + .createModification(processDefinition.getId()) + .startTransition("seq") + .processInstanceQuery(processInstanceQuery) + .historicProcessInstanceQuery(historicProcessInstanceQuery) + .executeAsync(); + + // then a batch is created + assertBatchCreated(batch, processInstanceCount); + } + @Test public void testListenerInvocation() { // given diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/ModificationExecutionSyncTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/ModificationExecutionSyncTest.java index 2e5abccefe9..aa08975f4fb 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/ModificationExecutionSyncTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/ModificationExecutionSyncTest.java @@ -29,13 +29,16 @@ import java.util.Collections; import java.util.List; +import org.operaton.bpm.engine.HistoryService; import org.operaton.bpm.engine.ProcessEngineException; import org.operaton.bpm.engine.RuntimeService; +import org.operaton.bpm.engine.history.HistoricProcessInstanceQuery; import org.operaton.bpm.engine.impl.persistence.entity.ExecutionEntity; import org.operaton.bpm.engine.repository.DeploymentWithDefinitions; import org.operaton.bpm.engine.repository.ProcessDefinition; import org.operaton.bpm.engine.runtime.ActivityInstance; import org.operaton.bpm.engine.runtime.Execution; +import org.operaton.bpm.engine.runtime.ProcessInstanceQuery; import org.operaton.bpm.engine.task.Task; import org.operaton.bpm.engine.test.ProcessEngineRule; import org.operaton.bpm.engine.test.util.ProcessEngineTestRule; @@ -59,6 +62,7 @@ public class ModificationExecutionSyncTest { public RuleChain ruleChain = RuleChain.outerRule(rule).around(testRule); protected RuntimeService runtimeService; + protected HistoryService historyService; protected BpmnModelInstance instance; @Before @@ -76,6 +80,7 @@ public void createBpmnModelInstance() { @Before public void initServices() { runtimeService = rule.getRuntimeService(); + historyService = rule.getHistoryService(); } @After @@ -97,6 +102,78 @@ public void createSimpleModificationPlan() { } } + @Test + public void createSimpleModificationPlanWithHistoricQuery() { + ProcessDefinition processDefinition = testRule.deployAndGetDefinition(instance); + List instances = helper.startInstances("process1", 2); + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery(); + historicProcessInstanceQuery.processDefinitionId(processDefinition.getId()); + + runtimeService.createModification(processDefinition.getId()).startBeforeActivity("user2") + .cancelAllForActivity("user1").historicProcessInstanceQuery(historicProcessInstanceQuery).execute(); + + for (String instanceId : instances) { + List activeActivityIds = runtimeService.getActiveActivityIds(instanceId); + assertEquals(1, activeActivityIds.size()); + assertEquals(activeActivityIds.iterator().next(), "user2"); + } + } + + @Test + public void createSimpleModificationPlanWithIdenticalRuntimeAndHistoryQuery() { + ProcessDefinition processDefinition = testRule.deployAndGetDefinition(instance); + List instances = helper.startInstances("process1", 2); + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery(); + historicProcessInstanceQuery.processDefinitionId(processDefinition.getId()); + ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery(); + processInstanceQuery.processDefinitionId(processDefinition.getId()); + + runtimeService.createModification(processDefinition.getId()).startBeforeActivity("user2") + .cancelAllForActivity("user1").historicProcessInstanceQuery(historicProcessInstanceQuery).processInstanceQuery(processInstanceQuery).execute(); + + for (String instanceId : instances) { + List activeActivityIds = runtimeService.getActiveActivityIds(instanceId); + assertEquals(1, activeActivityIds.size()); + assertEquals(activeActivityIds.iterator().next(), "user2"); + } + } + + @Test + public void createSimpleModificationPlanWithComplementaryRuntimeAndHistoryQueries() { + ProcessDefinition processDefinition = testRule.deployAndGetDefinition(instance); + List instances = helper.startInstances("process1", 2); + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery(); + historicProcessInstanceQuery.processInstanceId(instances.get(0)); + ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery(); + processInstanceQuery.processInstanceId(instances.get(1)); + + runtimeService.createModification(processDefinition.getId()).startBeforeActivity("user2") + .cancelAllForActivity("user1").historicProcessInstanceQuery(historicProcessInstanceQuery).processInstanceQuery(processInstanceQuery).execute(); + + for (String instanceId : instances) { + List activeActivityIds = runtimeService.getActiveActivityIds(instanceId); + assertEquals(1, activeActivityIds.size()); + assertEquals(activeActivityIds.iterator().next(), "user2"); + } + } + + @Test + public void createSimpleModificationPlanWithHistoricQueryUnfinished() { + ProcessDefinition processDefinition = testRule.deployAndGetDefinition(instance); + List instances = helper.startInstances("process1", 2); + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery(); + historicProcessInstanceQuery.processDefinitionId(processDefinition.getId()).unfinished(); + + runtimeService.deleteProcessInstance(instances.get(0), "test"); + + runtimeService.createModification(processDefinition.getId()).startBeforeActivity("user2") + .cancelAllForActivity("user1").historicProcessInstanceQuery(historicProcessInstanceQuery).execute(); + + List activeActivityIds = runtimeService.getActiveActivityIds(instances.get(1)); + assertEquals(1, activeActivityIds.size()); + assertEquals(activeActivityIds.iterator().next(), "user2"); + } + @Test public void createModificationWithNullProcessInstanceIdsList() { @@ -174,6 +251,16 @@ public void testNullProcessInstanceQuery() { } } + @Test + public void testNullHistoricProcessInstanceQuery() { + try { + runtimeService.createModification("processDefinitionId").startAfterActivity("user1").historicProcessInstanceQuery(null).execute(); + fail("Should not succeed"); + } catch (ProcessEngineException e) { + assertThat(e.getMessage()).contains("Process instance ids is empty"); + } + } + @Test public void createModificationWithNotMatchingProcessDefinitionId() { DeploymentWithDefinitions deployment = testRule.deploy(instance); diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/RestartProcessInstanceAsyncTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/RestartProcessInstanceAsyncTest.java index d119c317319..18351ad5360 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/RestartProcessInstanceAsyncTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/RestartProcessInstanceAsyncTest.java @@ -48,6 +48,7 @@ import org.operaton.bpm.engine.impl.cfg.multitenancy.TenantIdProviderCaseInstanceContext; import org.operaton.bpm.engine.impl.cfg.multitenancy.TenantIdProviderHistoricDecisionInstanceContext; import org.operaton.bpm.engine.impl.cfg.multitenancy.TenantIdProviderProcessInstanceContext; +import org.operaton.bpm.engine.impl.persistence.entity.HistoricProcessInstanceEntity; import org.operaton.bpm.engine.impl.util.ClockUtil; import org.operaton.bpm.engine.repository.ProcessDefinition; import org.operaton.bpm.engine.runtime.ActivityInstance; @@ -248,6 +249,46 @@ public void shouldRestartProcessInstance() { Assert.assertEquals(task2.getTaskDefinitionKey(), restartedTask.getTaskDefinitionKey()); } + @Test + public void shouldAssignRestartProcessInstanceIdOnlyToRestartedProcessInstances() { + // given process instances 1 and 2 + ProcessDefinition processDefinition = testRule.deployAndGetDefinition(ProcessModels.TWO_TASKS_PROCESS); + + var processInstance1 = runtimeService.startProcessInstanceByKey("Process"); + var processInstance2 = runtimeService.startProcessInstanceByKey("Process"); + + runtimeService.deleteProcessInstance(processInstance1.getId(), "test"); + runtimeService.deleteProcessInstance(processInstance2.getId(), "test"); + + // when process instance 1 is restarted + Batch batch = runtimeService.restartProcessInstances(processDefinition.getId()) + .startBeforeActivity("userTask1") + .processInstanceIds(processInstance1.getId()) + .executeAsync(); + + helper.completeSeedJobs(batch); + + helper.getExecutionJobs(batch).forEach(j -> assertEquals(processDefinition.getDeploymentId(), j.getDeploymentId())); + helper.completeExecutionJobs(batch); + helper.completeMonitorJobs(batch); + + // then the restartedProcessInstanceId should be populated only for the restarted process instance 1 + var restartedProcessInstance = runtimeService.createProcessInstanceQuery() + .active() + .singleResult(); + + var historicProcessInstance1 = (HistoricProcessInstanceEntity) historyService.createHistoricProcessInstanceQuery() + .processInstanceId(restartedProcessInstance.getId()) + .singleResult(); + + var historicProcessInstance2 = (HistoricProcessInstanceEntity) historyService.createHistoricProcessInstanceQuery() + .processInstanceId(processInstance2.getId()) + .singleResult(); + + assertThat(historicProcessInstance1.getRestartedProcessInstanceId()).isEqualTo(processInstance1.getId()); + assertThat(historicProcessInstance2.getRestartedProcessInstanceId()).isNull(); + } + @Test public void shouldRestartProcessInstanceWithParallelGateway() { // given diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/RestartProcessInstanceSyncTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/RestartProcessInstanceSyncTest.java index d79c8abca82..5ee3d46f066 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/RestartProcessInstanceSyncTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/api/runtime/RestartProcessInstanceSyncTest.java @@ -44,6 +44,7 @@ import org.operaton.bpm.engine.impl.cfg.multitenancy.TenantIdProviderHistoricDecisionInstanceContext; import org.operaton.bpm.engine.impl.cfg.multitenancy.TenantIdProviderProcessInstanceContext; import org.operaton.bpm.engine.impl.history.event.HistoricVariableUpdateEventEntity; +import org.operaton.bpm.engine.impl.persistence.entity.HistoricProcessInstanceEntity; import org.operaton.bpm.engine.repository.ProcessDefinition; import org.operaton.bpm.engine.runtime.ActivityInstance; import org.operaton.bpm.engine.runtime.Execution; @@ -122,6 +123,10 @@ public void shouldRestartSimpleProcessInstance() { ProcessInstance restartedProcessInstance = runtimeService.createProcessInstanceQuery().active().singleResult(); Task restartedTask = engineRule.getTaskService().createTaskQuery().processInstanceId(restartedProcessInstance.getId()).active().singleResult(); Assert.assertEquals(task.getTaskDefinitionKey(), restartedTask.getTaskDefinitionKey()); + + HistoricProcessInstanceEntity historicProcessInstanceEntity = (HistoricProcessInstanceEntity) historyService.createHistoricProcessInstanceQuery().processInstanceId(restartedProcessInstance.getId()).singleResult(); + Assert.assertEquals(processInstance.getId(), historicProcessInstanceEntity.getRestartedProcessInstanceId()); + } @Test diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/api/task/TaskQueryTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/api/task/TaskQueryTest.java index b15226cc40f..1214a2f5498 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/api/task/TaskQueryTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/api/task/TaskQueryTest.java @@ -33,8 +33,10 @@ import static org.operaton.bpm.engine.test.api.runtime.TestOrderingUtil.taskByProcessInstanceId; import static org.operaton.bpm.engine.test.api.runtime.TestOrderingUtil.verifySortingAndCount; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -55,6 +57,7 @@ import java.util.stream.Collectors; import org.operaton.bpm.engine.BadUserRequestException; +import org.operaton.bpm.engine.ProcessEngineConfiguration; import org.operaton.bpm.engine.ProcessEngineException; import org.operaton.bpm.engine.exception.NullValueException; import org.operaton.bpm.engine.filter.Filter; @@ -72,6 +75,7 @@ import org.operaton.bpm.engine.task.Task; import org.operaton.bpm.engine.task.TaskQuery; import org.operaton.bpm.engine.test.Deployment; +import org.operaton.bpm.engine.test.RequiredHistoryLevel; import org.operaton.bpm.engine.test.util.PluggableProcessEngineTest; import org.operaton.bpm.engine.variable.Variables; import org.operaton.bpm.engine.variable.type.ValueType; @@ -610,6 +614,70 @@ public void testQueryByIncludeAssignedTasksWithMissingCandidateUserOrGroup() { } } + @Test + public void testQueryByIncludeAssignedTasksWithoutMissingCandidateUserOrGroup() { + // We expect no exceptions when the there is at least 1 candidate user or group present + try { + taskService.createTaskQuery().taskCandidateUser("user").includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a taskCandidateUser is present"); + } + + try { + taskService.createTaskQuery().taskCandidateGroupLike("%group%").includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a candidateGroupLike is present"); + } + + try { + taskService.createTaskQuery().taskCandidateGroupIn(List.of("group")).includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a taskCandidateGroupIn is present"); + } + + try { + taskService.createTaskQuery().withCandidateGroups().includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a withCandidateGroups is present"); + } + + try { + taskService.createTaskQuery().withoutCandidateGroups().includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a withoutCandidateGroups is present"); + } + + try { + taskService.createTaskQuery().withCandidateUsers().includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a withCandidateUsers is present"); + } + + try { + taskService.createTaskQuery().withoutCandidateUsers().includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a withoutCandidateUsers is present"); + } + + try { + taskService.createTaskQuery().taskCandidateUserExpression("expression").includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a taskCandidateUserExpression is present"); + } + + try { + taskService.createTaskQuery().taskCandidateGroupExpression("expression").includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a taskCandidateGroupExpression is present"); + } + + try { + taskService.createTaskQuery().taskCandidateGroupInExpression("expression").includeAssignedTasks(); + } catch (ProcessEngineException e) { + fail("We expect no exceptions when a taskCandidateGroupInExpression is present"); + } + } + @Test public void testQueryByCandidateGroup() { // management group is candidate for 3 tasks, one of them is already assigned @@ -650,6 +718,58 @@ public void testQueryByCandidateGroup() { assertEquals(0, query.list().size()); } + @Test + public void testQueryByCandidateGroupLike() { + // management group is candidate for 3 tasks, one of them is already assigned + TaskQuery query = taskService.createTaskQuery().taskCandidateGroupLike("management"); + assertEquals(2, query.count()); + assertEquals(2, query.list().size()); + assertThrows(ProcessEngineException.class, query::singleResult); + + // test with "shortened" group name for like query + query = taskService.createTaskQuery().taskCandidateGroupLike("mana%"); + assertEquals(2, query.count()); + assertEquals(2, query.list().size()); + assertThrows(ProcessEngineException.class, query::singleResult); + + // test with "shortened" group name for like query (different part) + query = taskService.createTaskQuery().taskCandidateGroupLike("%ment"); + assertEquals(2, query.count()); + assertEquals(2, query.list().size()); + assertThrows(ProcessEngineException.class, query::singleResult); + + // test management candidates group with assigned tasks included + query = taskService.createTaskQuery().taskCandidateGroupLike("management").includeAssignedTasks(); + assertEquals(3, query.count()); + assertEquals(3, query.list().size()); + assertThrows(ProcessEngineException.class, query::singleResult); + + // test with "shortened" group name for like query (assigned tasks included) + query = taskService.createTaskQuery().taskCandidateGroupLike("mana%").includeAssignedTasks(); + assertEquals(3, query.count()); + assertEquals(3, query.list().size()); + assertThrows(ProcessEngineException.class, query::singleResult); + + // test with "shortened" group name for like query (different part, assigned tasks included) + query = taskService.createTaskQuery().taskCandidateGroupLike("%ment").includeAssignedTasks(); + assertEquals(3, query.count()); + assertEquals(3, query.list().size()); + assertThrows(ProcessEngineException.class, query::singleResult); + + // test query that matches tasks with the "management" the "accountancy" candidate groups + // accountancy group is candidate for 3 tasks, one of them is already assigned + query = taskService.createTaskQuery().taskCandidateGroupLike("%an%"); + assertEquals(4, query.count()); + assertEquals(4, query.list().size()); + assertThrows(ProcessEngineException.class, query::singleResult); + + // test query that matches tasks with the "management" the "accountancy" candidate groups (assigned tasks included) + query = taskService.createTaskQuery().taskCandidateGroupLike("%an%").includeAssignedTasks(); + assertEquals(5, query.count()); + assertEquals(5, query.list().size()); + assertThrows(ProcessEngineException.class, query::singleResult); + } + @Test public void testQueryWithCandidateGroups() { // test withCandidateGroups @@ -5602,7 +5722,39 @@ public void shouldFindStandaloneTaskWithUpdateByLastUpdated() { assertThat(taskResult.getLastUpdated()).isAfter(beforeSave); assertThat(taskResult.getLastUpdated()).isAfter(taskResult.getCreateTime()); } - + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_ACTIVITY) + @Deployment(resources = "org/operaton/bpm/engine/test/api/oneTaskProcess.bpmn20.xml") + public void shouldNotFindAttachmentAndCommentInfoWithoutQueryParam() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess"); + Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + task.setAssignee("myself"); + // when + taskService.createComment(task.getId(), processInstance.getId(), "testComment"); + taskService.createAttachment("foo", task.getId(), processInstance.getId(), "testAttachment", "testDesc", "http://operaton.org"); + // then + Task taskResult = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + assertThat(taskResult).isNotNull(); + assertFalse(taskResult.hasComment()); + assertFalse(taskResult.hasAttachment()); + } + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_ACTIVITY) + @Deployment(resources = "org/operaton/bpm/engine/test/api/oneTaskProcess.bpmn20.xml") + public void shouldFindAttachmentAndCommentInfoWithQueryParam() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess"); + Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + // when + taskService.createComment(task.getId(), processInstance.getId(), "testComment"); + taskService.createAttachment("foo", task.getId(), processInstance.getId(), "testAttachment", "testDesc", "http://operaton.org"); + // then + Task taskResult = taskService.createTaskQuery().processInstanceId(processInstance.getId()).withCommentAttachmentInfo().singleResult(); + assertThat(taskResult).isNotNull(); + assertTrue(taskResult.hasComment()); + assertTrue(taskResult.hasAttachment()); + } // ---------------------- HELPER ------------------------------ // make sure that time passes between two fast operations diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/history/HistoricProcessInstanceStateTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/history/HistoricProcessInstanceStateTest.java index a9c066c5bc0..e0e42c61990 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/history/HistoricProcessInstanceStateTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/history/HistoricProcessInstanceStateTest.java @@ -83,6 +83,8 @@ public void testCompletedOnEndEvent() { ProcessDefinition processDefinition = processEngineTestRule.deployAndGetDefinition(instance); processEngineRule.getRuntimeService().startProcessInstanceById(processDefinition.getId()); HistoricProcessInstance entity = getHistoricProcessInstanceWithAssertion(processDefinition); + + assertThat(entity.getRestartedProcessInstanceId()).isNull(); assertThat(entity.getState()).isEqualTo(HistoricProcessInstance.STATE_COMPLETED); } diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/history/HistoricProcessInstanceTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/history/HistoricProcessInstanceTest.java index 954e395d77f..18c52f1aaca 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/history/HistoricProcessInstanceTest.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/history/HistoricProcessInstanceTest.java @@ -36,9 +36,12 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.lang3.time.DateUtils; import org.operaton.bpm.engine.BadUserRequestException; import org.operaton.bpm.engine.CaseService; @@ -57,16 +60,22 @@ import org.operaton.bpm.engine.history.HistoricVariableInstance; import org.operaton.bpm.engine.impl.history.HistoryLevel; import org.operaton.bpm.engine.impl.history.event.HistoricProcessInstanceEventEntity; +import org.operaton.bpm.engine.impl.persistence.entity.JobEntity; import org.operaton.bpm.engine.impl.util.ClockUtil; import org.operaton.bpm.engine.repository.ProcessDefinition; +import org.operaton.bpm.engine.runtime.Incident; import org.operaton.bpm.engine.runtime.Job; import org.operaton.bpm.engine.runtime.ProcessInstance; +import org.operaton.bpm.engine.runtime.ProcessInstanceQuery; import org.operaton.bpm.engine.task.Task; import org.operaton.bpm.engine.test.Deployment; import org.operaton.bpm.engine.test.ProcessEngineRule; import org.operaton.bpm.engine.test.RequiredHistoryLevel; +import org.operaton.bpm.engine.test.api.mgmt.FailingDelegate; import org.operaton.bpm.engine.test.api.runtime.migration.models.CallActivityModels; +import org.operaton.bpm.engine.test.api.runtime.migration.models.CompensationModels; import org.operaton.bpm.engine.test.api.runtime.migration.models.ProcessModels; +import org.operaton.bpm.engine.test.api.runtime.util.ChangeVariablesDelegate; import org.operaton.bpm.engine.test.util.ProcessEngineTestRule; import org.operaton.bpm.engine.test.util.ProvidedProcessEngineRule; import org.operaton.bpm.engine.variable.Variables; @@ -87,6 +96,23 @@ public class HistoricProcessInstanceTest { public ProcessEngineRule engineRule = new ProvidedProcessEngineRule(); public ProcessEngineTestRule testHelper = new ProcessEngineTestRule(engineRule); + public static final BpmnModelInstance FORK_JOIN_SUB_PROCESS_MODEL = ProcessModels.newModel() + .startEvent() + .subProcess("subProcess") + .embeddedSubProcess() + .startEvent() + .parallelGateway("fork") + .userTask("userTask1") + .name("completeMe") + .parallelGateway("join") + .endEvent() + .moveToNode("fork") + .userTask("userTask2") + .connectTo("join") + .subProcessDone() + .endEvent() + .done(); + @Rule public RuleChain chain = RuleChain.outerRule(engineRule).around(testHelper); @@ -1546,6 +1572,556 @@ public void testHistoricProcInstQueryWithActiveActivityIds() { assertEquals(result.get(0).getId(), processInstance.getId()); } + @Test + public void testQueryByNullActivityId() { + try { + historyService.createHistoricProcessInstanceQuery().activeActivityIdIn((String[]) null).list(); + fail("exception expected"); + } + catch (BadUserRequestException e) { + assertThat(e.getMessage()).contains("activity ids is null"); + } + } + + @Test + public void testQueryByNullActivityIds() { + try { + historyService.createHistoricProcessInstanceQuery() + .activityIdIn((String[]) null); + fail("exception expected"); + } + catch (BadUserRequestException e) { + assertThat(e.getMessage()).contains("activity ids is null"); + } + } + + @Test + public void testQueryByUnknownActivityId() { + HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery() + .activityIdIn("unknown"); + + assertEquals(0, query.count()); + assertEquals(0, query.list().size()); + } + + @Test + public void testQueryByLeafActivityId() { + // given + ProcessDefinition oneTaskDefinition = testHelper.deployAndGetDefinition(ProcessModels.ONE_TASK_PROCESS); + ProcessDefinition gatewaySubProcessDefinition = testHelper.deployAndGetDefinition(FORK_JOIN_SUB_PROCESS_MODEL); + + // when + ProcessInstance oneTaskInstance1 = runtimeService.startProcessInstanceById(oneTaskDefinition.getId()); + ProcessInstance oneTaskInstance2 = runtimeService.startProcessInstanceById(oneTaskDefinition.getId()); + ProcessInstance gatewaySubProcessInstance1 = runtimeService.startProcessInstanceById(gatewaySubProcessDefinition.getId()); + ProcessInstance gatewaySubProcessInstance2 = runtimeService.startProcessInstanceById(gatewaySubProcessDefinition.getId()); + + Task task = engineRule.getTaskService().createTaskQuery() + .processInstanceId(gatewaySubProcessInstance2.getId()) + .taskName("completeMe") + .singleResult(); + engineRule.getTaskService().complete(task.getId()); + + // then + HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().activityIdIn("userTask"); + assertReturnedProcessInstances(query, oneTaskInstance1, oneTaskInstance2); + + query = historyService.createHistoricProcessInstanceQuery().activityIdIn("userTask1", "userTask2"); + assertReturnedProcessInstances(query, gatewaySubProcessInstance1, gatewaySubProcessInstance2); + + query = historyService.createHistoricProcessInstanceQuery().activityIdIn("userTask", "userTask1"); + assertReturnedProcessInstances(query, oneTaskInstance1, oneTaskInstance2, gatewaySubProcessInstance1); + + query = historyService.createHistoricProcessInstanceQuery().activityIdIn("userTask", "userTask1", "userTask2"); + assertReturnedProcessInstances(query, oneTaskInstance1, oneTaskInstance2, gatewaySubProcessInstance1, gatewaySubProcessInstance2); + + query = historyService.createHistoricProcessInstanceQuery().activityIdIn("join"); + assertReturnedProcessInstances(query, gatewaySubProcessInstance2); + } + + @Test + public void testQueryByNonLeafActivityId() { + // given + ProcessDefinition processDefinition = testHelper.deployAndGetDefinition(FORK_JOIN_SUB_PROCESS_MODEL); + + // when + runtimeService.startProcessInstanceById(processDefinition.getId()); + + // then + ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().activityIdIn("subProcess", "fork"); + + assertEquals(0, query.count()); + assertEquals(0, query.list().size()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + public void testQueryByAsyncBeforeActivityId() { + // For a historic instance when AsyncBefore is used the historic activity is only created when the execution is scheduled + // For process instances that have a token just before a AsyncBefore activity + // In the runtimeInstanceQuery activityIdIn filter returns instances that are not scheduled yet + // In historicInstanceQuery activityIdIn filter does not return instances that are not scheduled yet + + // given + ProcessDefinition testProcess = testHelper.deployAndGetDefinition(ProcessModels.newModel() + .startEvent("start").operatonAsyncBefore() + .subProcess("subProcess").operatonAsyncBefore() + .embeddedSubProcess() + .startEvent() + .serviceTask("task").operatonAsyncBefore().operatonExpression("${true}") + .endEvent() + .subProcessDone() + .endEvent("end").operatonAsyncBefore() + .done() + ); + + // when + ProcessInstance instanceBeforeStart = runtimeService.startProcessInstanceById(testProcess.getId()); + ProcessInstance instanceBeforeSubProcess = runtimeService.startProcessInstanceById(testProcess.getId()); + executeJobForProcessInstance(instanceBeforeSubProcess); + ProcessInstance instanceBeforeTask = runtimeService.startProcessInstanceById(testProcess.getId()); + executeJobForProcessInstance(instanceBeforeTask); + executeJobForProcessInstance(instanceBeforeTask); + ProcessInstance instanceBeforeEnd = runtimeService.startProcessInstanceById(testProcess.getId()); + executeJobForProcessInstance(instanceBeforeEnd); + executeJobForProcessInstance(instanceBeforeEnd); + executeJobForProcessInstance(instanceBeforeEnd); + + // then + HistoricProcessInstanceQuery historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("start"); + assertNull(historicQuery.singleResult()); + ProcessInstanceQuery runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("start"); + assertEquals(instanceBeforeStart.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + + historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("subProcess"); + assertReturnedProcessInstances(historicQuery, instanceBeforeTask); + runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("subProcess"); + assertEquals(instanceBeforeSubProcess.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + + historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("task"); + assertNull(historicQuery.singleResult()); + runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("task"); + assertEquals(instanceBeforeTask.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + + historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("end"); + assertNull(historicQuery.singleResult()); + runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("end"); + assertEquals(instanceBeforeEnd.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + public void testQueryByAsyncAfterActivityId() { + // For a historic activity the end time is set after it is executed => the activity is not considered active anymore, + // this is not changed if AsyncAfter is used + // if the task is a subprocess end time will only be set after the subprocess is terminated + // For the runtime query the execution is still visible if AsyncAfter is used (I assume we delete the execution when scheduling next activity) + + // given + ProcessDefinition testProcess = testHelper.deployAndGetDefinition(ProcessModels.newModel() + .startEvent("start").operatonAsyncAfter() + .subProcess("subProcess").operatonAsyncAfter() + .embeddedSubProcess() + .startEvent() + .serviceTask("task").operatonAsyncAfter().operatonExpression("${true}") + .endEvent() + .subProcessDone() + .endEvent("end").operatonAsyncAfter() + .done() + ); + + // when + ProcessInstance instanceAfterStart = runtimeService.startProcessInstanceById(testProcess.getId()); + ProcessInstance instanceAfterTask = runtimeService.startProcessInstanceById(testProcess.getId()); + executeJobForProcessInstance(instanceAfterTask); + ProcessInstance instanceAfterSubProcess = runtimeService.startProcessInstanceById(testProcess.getId()); + executeJobForProcessInstance(instanceAfterSubProcess); + executeJobForProcessInstance(instanceAfterSubProcess); + ProcessInstance instanceAfterEnd = runtimeService.startProcessInstanceById(testProcess.getId()); + executeJobForProcessInstance(instanceAfterEnd); + executeJobForProcessInstance(instanceAfterEnd); + executeJobForProcessInstance(instanceAfterEnd); + + HistoricProcessInstanceQuery historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("start"); + assertNull(historicQuery.singleResult()); + ProcessInstanceQuery runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("start"); + assertEquals(instanceAfterStart.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + + historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("task"); + assertNull(historicQuery.singleResult()); + runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("task"); + assertEquals(instanceAfterTask.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + + historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("subProcess"); + assertReturnedProcessInstances(historicQuery, instanceAfterTask); + runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("subProcess"); + assertEquals(instanceAfterSubProcess.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + + historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("end"); + assertNull(historicQuery.singleResult()); + runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("end"); + assertEquals(instanceAfterEnd.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + } + + @Test + public void testQueryByActivityIdBeforeCompensation() { + // given + ProcessDefinition testProcess = testHelper.deployAndGetDefinition(CompensationModels.COMPENSATION_ONE_TASK_SUBPROCESS_MODEL); + + // when + runtimeService.startProcessInstanceById(testProcess.getId()); + testHelper.completeTask("userTask1"); + + // then + ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().activityIdIn("subProcess"); + + assertEquals(0, query.count()); + assertEquals(0, query.list().size()); } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + public void testQueryByActivityIdDuringCompensation() { + // After completing user task we are expecting "subProcess", "compensationEvent", "compensationHandler" to have an activity + // Based on historic data only "compensationEvent", "compensationHandler" have active events + + // given + ProcessDefinition testProcess = testHelper.deployAndGetDefinition(CompensationModels.COMPENSATION_ONE_TASK_SUBPROCESS_MODEL); + + // when + ProcessInstance processInstance = runtimeService.startProcessInstanceById(testProcess.getId()); + testHelper.completeTask("userTask1"); + testHelper.completeTask("userTask2"); + + // then + HistoricProcessInstanceQuery historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("subProcess"); + assertNull(historicQuery.singleResult()); + ProcessInstanceQuery runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("subProcess"); + assertEquals(processInstance.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + + historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("compensationEvent"); + assertReturnedProcessInstances(historicQuery, processInstance); + runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("compensationEvent"); + assertEquals(processInstance.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + + historicQuery = historyService.createHistoricProcessInstanceQuery().activityIdIn("compensationHandler"); + assertReturnedProcessInstances(historicQuery, processInstance); + runtimeQuery = runtimeService.createProcessInstanceQuery().activityIdIn("compensationEvent"); + assertEquals(processInstance.getId(), runtimeQuery.singleResult().getProcessInstanceId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + public void testHistoricProcInstQueryWithActivityIdsWithOneId() { + // given + String USER_TASK_1 = "userTask1"; + deployment(ProcessModels.TWO_TASKS_PROCESS); + runtimeService.startProcessInstanceByKey("Process"); + runtimeService.startProcessInstanceByKey("Process"); + + List tasks = taskService.createTaskQuery().list(); + assertEquals(2, tasks.size()); + taskService.complete(tasks.get(0).getId()); + + // when + List result = historyService + .createHistoricProcessInstanceQuery() + .activityIdIn(USER_TASK_1) + .list(); + + // then + assertNotNull(result); + assertEquals(1, result.size()); + assertEquals(result.get(0).getId(), tasks.get(1).getProcessInstanceId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + public void testHistoricProcInstQueryWithActivityIdsWithMultipleIds() { + // given + String USER_TASK_1 = "userTask1"; + String USER_TASK_2 = "userTask2"; + deployment(ProcessModels.TWO_TASKS_PROCESS); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process"); + ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("Process"); + + List tasks = taskService.createTaskQuery().list(); + assertEquals(2, tasks.size()); + taskService.complete(tasks.get(0).getId()); + + // when + List result = historyService + .createHistoricProcessInstanceQuery() + .activityIdIn(USER_TASK_1, USER_TASK_2) + .list(); + + // then + assertNotNull(result); + assertEquals(2, result.size()); + assertThat(result.stream().map(HistoricProcessInstance::getId).collect(Collectors.toList())) + .containsExactlyInAnyOrder(processInstance.getId(),processInstance2.getId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + public void testHistoricProcInstQueryWithActivityIdsWhenDeletedCompetedInstancesExist() { + // given + String USER_TASK_1 = "userTask1"; + String USER_TASK_2 = "userTask2"; + deployment(ProcessModels.TWO_TASKS_PROCESS); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process"); + ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("Process"); + + List tasks = taskService.createTaskQuery().list(); + assertEquals(2, tasks.size()); + taskService.complete(tasks.get(0).getId()); + + ProcessInstance completedProcessInstance = runtimeService.startProcessInstanceByKey("Process"); + Task task = taskService.createTaskQuery().processInstanceId(completedProcessInstance.getId()).singleResult(); + taskService.complete(task.getId()); + task = taskService.createTaskQuery().processInstanceId(completedProcessInstance.getId()).singleResult(); + taskService.complete(task.getId()); + + + ProcessInstance deletedProcessInstance = runtimeService.startProcessInstanceByKey("Process"); + runtimeService.deleteProcessInstance(deletedProcessInstance.getId(), "Testing"); + + // when + List result = historyService + .createHistoricProcessInstanceQuery() + .activityIdIn(USER_TASK_1, USER_TASK_2) + .list(); + + // then + assertNotNull(result); + assertEquals(2, result.size()); + assertThat(result.stream().map(HistoricProcessInstance::getId).collect(Collectors.toList())) + .containsExactlyInAnyOrder(processInstance.getId(), processInstance2.getId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources = {"org/operaton/bpm/engine/test/history/HistoricProcessInstanceTest.testHistoricProcessInstanceQueryActivityIdInWithIncident.bpmn"}) + public void testHistoricProcInstQueryWithActivityIdsWithFailingActivity() { + // given + runtimeService.startProcessInstanceByKey("failingProcess"); + testHelper.executeAvailableJobs(); + + runtimeService.startProcessInstanceByKey("failingProcess"); + + // assume + assertEquals(2, historyService.createHistoricProcessInstanceQuery().count()); + assertEquals(2, historyService.createHistoricProcessInstanceQuery().list().size()); + + assertEquals(1, historyService.createHistoricProcessInstanceQuery().withIncidents().count()); + assertEquals(1, historyService.createHistoricProcessInstanceQuery().withIncidents().list().size()); + HistoricProcessInstance failingInstance = historyService.createHistoricProcessInstanceQuery().withIncidents().singleResult(); + + // when + List result = historyService + .createHistoricProcessInstanceQuery() + .activityIdIn("serviceTask") + .list(); + + // then + assertNotNull(result); + assertEquals(1, result.size()); + assertEquals(result.get(0).getId(), failingInstance.getId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/failingSubProcessCreateOneIncident.bpmn20.xml"}) + public void shouldQueryByActivityIdInWithActivityIdOfFailingSubprocess() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("failingSubProcess"); + + testHelper.executeAvailableJobs(); + + // when + HistoricProcessInstance historicPI = + historyService.createHistoricProcessInstanceQuery().activityIdIn("subProcess").singleResult(); + + // then + assertThat(historicPI).isNotNull(); + assertThat(historicPI.getId()).isEqualTo(processInstance.getId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/failingSubProcessCreateOneIncident.bpmn20.xml"}) + public void shouldQueryByActivityIdInWithActivityIdOfFailingSubServiceTask() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("failingSubProcess"); + + testHelper.executeAvailableJobs(); + + // when + HistoricProcessInstance historicPI = + historyService.createHistoricProcessInstanceQuery().activityIdIn("serviceTask").singleResult(); + + // then + assertThat(historicPI).isNotNull(); + assertThat(historicPI.getId()).isEqualTo(processInstance.getId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.subprocess.bpmn20.xml"}) + public void shouldQueryByActivityIdInWithActivityIdOfSubprocess() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("subprocess"); + + TaskService taskService = engineRule.getTaskService(); + Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + assertNotNull(task); + taskService.complete(task.getId()); + // when + HistoricProcessInstance historicPI = + historyService.createHistoricProcessInstanceQuery().activityIdIn("subProcess").singleResult(); + + // then + assertThat(historicPI).isNotNull(); + assertThat(historicPI.getId()).isEqualTo(processInstance.getId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.subprocess.bpmn20.xml"}) + public void shouldQueryByActivityIdInWithActivityIdOfSubServiceTask() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("subprocess"); + + TaskService taskService = engineRule.getTaskService(); + Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + assertNotNull(task); + taskService.complete(task.getId()); + // when + HistoricProcessInstance historicPI = + historyService.createHistoricProcessInstanceQuery().activityIdIn("innerTask").singleResult(); + + // then + assertThat(historicPI).isNotNull(); + assertThat(historicPI.getId()).isEqualTo(processInstance.getId()); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.failingSubprocessWithAsyncBeforeTask.bpmn20.xml"}) + public void shouldQueryByActivityIdInWithMultipleScopeAndIncident() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("failingSubProcess"); + ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("failingSubProcess"); + + TaskService taskService = engineRule.getTaskService(); + Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + taskService.complete(task.getId()); + + testHelper.executeAvailableJobs(); + + // when + List queryByInnerServiceActivityId = + historyService.createHistoricProcessInstanceQuery().activityIdIn("innerServiceTask").list(); + List queryBySubProcessActivityId = + historyService.createHistoricProcessInstanceQuery().activityIdIn("subProcess").list(); + List queryByOuterProcessActivityId = + historyService.createHistoricProcessInstanceQuery().activityIdIn("outerTask").list(); + List queryByOuterAndInnedActivityId = + historyService.createHistoricProcessInstanceQuery().activityIdIn("innerServiceTask", "outerTask").list(); + + // then + assertThat(queryByInnerServiceActivityId.size()).isEqualTo(1); + assertThat(queryByInnerServiceActivityId.get(0).getId()).isEqualTo(processInstance.getId()); + + assertThat(queryBySubProcessActivityId.size()).isEqualTo(1); + assertThat(queryBySubProcessActivityId.get(0).getId()).isEqualTo(processInstance.getId()); + + assertThat(queryByOuterProcessActivityId.size()).isEqualTo(1); + assertThat(queryByOuterProcessActivityId.get(0).getId()).isEqualTo(processInstance2.getId()); + + assertThat(queryByOuterAndInnedActivityId.size()).isEqualTo(2); + assertThat(queryByOuterAndInnedActivityId.stream() + .map(HistoricProcessInstance::getId) + .collect(Collectors.toList())) + .containsExactlyInAnyOrderElementsOf(Arrays.asList(processInstance.getId(), processInstance2.getId())); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.subprocessWithAsyncBeforeTask.bpmn20.xml"}) + public void shouldQueryByActivityIdInWithMultipleScope() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("failingSubProcess"); + ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("failingSubProcess"); + + TaskService taskService = engineRule.getTaskService(); + Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + taskService.complete(task.getId()); + + // when + List queryByInnerServiceActivityId = + historyService.createHistoricProcessInstanceQuery().activityIdIn("innerTask").list(); + List queryBySubProcessActivityId = + historyService.createHistoricProcessInstanceQuery().activityIdIn("subProcess").list(); + List queryByOuterProcessActivityId = + historyService.createHistoricProcessInstanceQuery().activityIdIn("outerTask").list(); + List queryByOuterAndInnedActivityId = + historyService.createHistoricProcessInstanceQuery().activityIdIn("innerTask", "outerTask").list(); + + // then + assertThat(queryByInnerServiceActivityId.size()).isEqualTo(1); + assertThat(queryByInnerServiceActivityId.get(0).getId()).isEqualTo(processInstance.getId()); + + assertThat(queryBySubProcessActivityId.size()).isEqualTo(1); + assertThat(queryBySubProcessActivityId.get(0).getId()).isEqualTo(processInstance.getId()); + + assertThat(queryByOuterProcessActivityId.size()).isEqualTo(1); + assertThat(queryByOuterProcessActivityId.get(0).getId()).isEqualTo(processInstance2.getId()); + + assertThat(queryByOuterAndInnedActivityId.size()).isEqualTo(2); + assertThat(queryByOuterAndInnedActivityId.stream() + .map(HistoricProcessInstance::getId) + .collect(Collectors.toList())) + .containsExactlyInAnyOrderElementsOf(Arrays.asList(processInstance.getId(), processInstance2.getId())); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + public void shouldQueryByActivityIdWhereIncidentOccurred() { + // given + testHelper.deploy(Bpmn.createExecutableProcess("process") + .startEvent() + .serviceTask("theTask") + .operatonAsyncBefore() + .operatonClass(ChangeVariablesDelegate.class) + .serviceTask("theTask2").operatonClass(ChangeVariablesDelegate.class) + .serviceTask("theTask3").operatonClass(FailingDelegate.class) + .endEvent() + .done()); + + runtimeService.startProcessInstanceByKey("process", Variables.createVariables().putValue("fail", true)); + JobEntity job = (JobEntity) managementService.createJobQuery().singleResult(); + + // when: incident is raised + for(int i = 0; i<3; i++) { + try { + managementService.executeJob(job.getId()); + fail("Exception expected"); + } catch (Exception e) { + // exception expected + } + } + + // then + HistoricProcessInstance theTask = historyService.createHistoricProcessInstanceQuery() + .activityIdIn("theTask") + .singleResult(); + assertThat(theTask).isNotNull(); + HistoricProcessInstance theTask3 = historyService.createHistoricProcessInstanceQuery() + .activityIdIn("theTask3") + .singleResult(); + assertThat(theTask3).isNull(); + } + @Test public void testHistoricProcInstQueryWithActiveActivityIdsNull() { try { @@ -1693,6 +2269,100 @@ public void testQueryByMultipleInvalidProcessDefinitionKeyIn() { } } + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/failingProcessCreateOneIncident.bpmn20.xml"}) + public void shouldQueryProcessInstancesWithIncidentIdIn() { + // GIVEN + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("failingProcess"); + ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("failingProcess"); + runtimeService.startProcessInstanceByKey("failingProcess"); + List queriedProcessInstances = Arrays.asList(processInstance.getId(), processInstance2.getId()); + + testHelper.executeAvailableJobs(); + Incident incident = runtimeService.createIncidentQuery().processInstanceId(queriedProcessInstances.get(0)).singleResult(); + Incident incident2 = runtimeService.createIncidentQuery().processInstanceId(queriedProcessInstances.get(1)).singleResult(); + + // WHEN + List processInstanceList = + historyService.createHistoricProcessInstanceQuery().incidentIdIn(incident.getId(), incident2.getId()).list(); + + // THEN + assertEquals(2, processInstanceList.size()); + assertThat(queriedProcessInstances) + .containsExactlyInAnyOrderElementsOf( + processInstanceList.stream() + .map(HistoricProcessInstance::getId) + .collect(Collectors.toList())); + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/failingProcessAfterUserTaskCreateOneIncident.bpmn20.xml"}) + public void shouldOnlyQueryProcessInstancesWithIncidentIdIn() { + // GIVEN + ProcessInstance processWithIncident1 = runtimeService.startProcessInstanceByKey("failingProcess"); + ProcessInstance processWithIncident2 = runtimeService.startProcessInstanceByKey("failingProcess"); + + List tasks = taskService.createTaskQuery().list(); + assertEquals(2, tasks.size()); + taskService.complete(tasks.get(0).getId()); + taskService.complete(tasks.get(1).getId()); + + ProcessInstance processWithoutIncident = runtimeService.startProcessInstanceByKey("failingProcess"); + + List queriedProcessInstances = Arrays.asList(processWithIncident1.getId(), processWithIncident2.getId()); + + testHelper.executeAvailableJobs(); + Incident incident = runtimeService.createIncidentQuery().processInstanceId(queriedProcessInstances.get(0)).singleResult(); + Incident incident2 = runtimeService.createIncidentQuery().processInstanceId(queriedProcessInstances.get(1)).singleResult(); + + // WHEN + List processInstanceList = + historyService.createHistoricProcessInstanceQuery().incidentIdIn(incident.getId(), incident2.getId()).list(); + + // THEN + assertEquals(2, processInstanceList.size()); + assertThat(queriedProcessInstances) + .containsExactlyInAnyOrderElementsOf( + processInstanceList.stream() + .map(HistoricProcessInstance::getId) + .collect(Collectors.toList())); + } + + @Test + public void shouldFailWhenQueryWithNullIncidentIdIn() { + try { + historyService.createHistoricProcessInstanceQuery().incidentIdIn(null).list(); + fail("incidentMessage with null value is not allowed"); + } catch( NullValueException nex ) { + // expected + } + } + + @Test + @RequiredHistoryLevel(ProcessEngineConfiguration.HISTORY_FULL) + @Deployment(resources={"org/operaton/bpm/engine/test/api/runtime/failingSubProcessCreateOneIncident.bpmn20.xml"}) + public void shouldQueryByIncidentIdInSubProcess() { + // given + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("failingSubProcess"); + + testHelper.executeAvailableJobs(); + + List incidentList = runtimeService.createIncidentQuery().list(); + assertEquals(1, incidentList.size()); + + Incident incident = runtimeService.createIncidentQuery().processInstanceId(processInstance.getId()).singleResult(); + + // when + HistoricProcessInstance historicPI = + historyService.createHistoricProcessInstanceQuery().incidentIdIn(incident.getId()).singleResult(); + + // then + assertThat(historicPI).isNotNull(); + assertThat(historicPI.getId()).isEqualTo(processInstance.getId()); + } + @Test @Deployment(resources = {"org/operaton/bpm/engine/test/history/oneAsyncTaskProcess.bpmn20.xml"}) public void testShouldStoreHistoricProcessInstanceVariableOnAsyncBefore() { @@ -2009,4 +2679,39 @@ protected void executeJob(Job job) { } } + + protected void assertReturnedProcessInstances(HistoricProcessInstanceQuery query, ProcessInstance... processInstances) { + int expectedSize = processInstances.length; + assertEquals(expectedSize, query.count()); + assertEquals(expectedSize, query.list().size()); + + verifyResultContainsExactly(query.list(), collectProcessInstanceIds(Arrays.asList(processInstances))); + } + + protected void verifyResultContainsExactly(List instances, Set processInstanceIds) { + Set retrievedInstanceIds = collectHistoricProcessInstanceIds(instances); + assertEquals(processInstanceIds, retrievedInstanceIds); + } + + protected Set collectProcessInstanceIds(List instances) { + Set retrievedInstanceIds = new HashSet<>(); + for (ProcessInstance instance : instances) { + retrievedInstanceIds.add(instance.getId()); + } + return retrievedInstanceIds; + } + + protected Set collectHistoricProcessInstanceIds(List instances) { + Set retrievedInstanceIds = new HashSet<>(); + for (HistoricProcessInstance instance : instances) { + retrievedInstanceIds.add(instance.getId()); + } + return retrievedInstanceIds; + } + + protected void executeJobForProcessInstance(ProcessInstance processInstance) { + Job job = managementService.createJobQuery().processInstanceId(processInstance.getId()).singleResult(); + managementService.executeJob(job.getId()); + } + } diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/history/JobEntityAndJobLogBatchIdTest.java b/engine/src/test/java/org/operaton/bpm/engine/test/history/JobEntityAndJobLogBatchIdTest.java new file mode 100644 index 00000000000..3e4ee05e7b4 --- /dev/null +++ b/engine/src/test/java/org/operaton/bpm/engine/test/history/JobEntityAndJobLogBatchIdTest.java @@ -0,0 +1,469 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.operaton.bpm.engine.test.history; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; +import org.operaton.bpm.engine.DecisionService; +import org.operaton.bpm.engine.ExternalTaskService; +import org.operaton.bpm.engine.HistoryService; +import org.operaton.bpm.engine.ManagementService; +import org.operaton.bpm.engine.RuntimeService; +import org.operaton.bpm.engine.batch.Batch; +import org.operaton.bpm.engine.externaltask.ExternalTask; +import org.operaton.bpm.engine.history.HistoricDecisionInstanceQuery; +import org.operaton.bpm.engine.history.HistoricJobLog; +import org.operaton.bpm.engine.history.HistoricProcessInstanceQuery; +import org.operaton.bpm.engine.impl.batch.BatchMonitorJobHandler; +import org.operaton.bpm.engine.impl.batch.BatchSeedJobHandler; +import org.operaton.bpm.engine.migration.MigrationPlan; +import org.operaton.bpm.engine.repository.ProcessDefinition; +import org.operaton.bpm.engine.runtime.ActivityInstance; +import org.operaton.bpm.engine.runtime.Job; +import org.operaton.bpm.engine.runtime.ProcessInstance; +import org.operaton.bpm.engine.test.Deployment; +import org.operaton.bpm.engine.test.ProcessEngineRule; +import org.operaton.bpm.engine.test.api.history.removaltime.batch.helper.BatchSetRemovalTimeRule; +import org.operaton.bpm.engine.test.util.BatchRule; +import org.operaton.bpm.engine.test.util.ProcessEngineTestRule; +import org.operaton.bpm.engine.test.util.ProvidedProcessEngineRule; +import org.operaton.bpm.engine.variable.Variables; +import org.operaton.bpm.model.bpmn.Bpmn; +import org.operaton.bpm.model.bpmn.BpmnModelInstance; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; + +public class JobEntityAndJobLogBatchIdTest { + + protected ProcessEngineRule engineRule = new ProvidedProcessEngineRule(); + protected ProcessEngineTestRule testRule = new ProcessEngineTestRule(engineRule); + protected BatchRule batchRule = new BatchRule(engineRule, testRule); + protected BatchSetRemovalTimeRule batchRemovalTimeRule = new BatchSetRemovalTimeRule(engineRule, testRule); + + @Rule + public RuleChain ruleChain = RuleChain + .outerRule(engineRule) + .around(testRule) + .around(batchRule) + .around(batchRemovalTimeRule); + + protected RuntimeService runtimeService; + protected HistoryService historyService; + protected ManagementService managementService; + protected DecisionService decisionService; + protected ExternalTaskService externalTaskService; + + @Before + public void init() { + runtimeService = engineRule.getRuntimeService(); + historyService = engineRule.getHistoryService(); + managementService = engineRule.getManagementService(); + decisionService = engineRule.getDecisionService(); + externalTaskService = engineRule.getExternalTaskService(); + } + + private BpmnModelInstance getUserTaskProcess() { + return Bpmn.createExecutableProcess("process") + .startEvent() + .userTask("task1") + .endEvent() + .done(); + } + + private BpmnModelInstance getTwoUserTasksProcess() { + return Bpmn.createExecutableProcess("process") + .startEvent() + .userTask("task1") + .userTask("task2") + .endEvent() + .done(); + } + + private BpmnModelInstance getTimerProcess() { + return Bpmn.createExecutableProcess("process") + .startEvent() + .timerWithDuration("PT5H") + .endEvent() + .done(); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_SetHistoricBatchRemovalTime() { + // given + testRule.deploy(getUserTaskProcess()); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("process"); + + // create historic Batch + Batch setVariablesBatch = runtimeService.setVariablesAsync(List.of(processInstance.getId()), + Variables.createVariables().putValue("foo", "bar")); + batchRule.syncExec(setVariablesBatch); + + // set historic batch removal time + Batch setRemovalTimeBatch = historyService.setRemovalTimeToHistoricBatches() + .absoluteRemovalTime(batchRemovalTimeRule.REMOVAL_TIME) + .byQuery(historyService.createHistoricBatchQuery()) + .executeAsync(); + + // when + Map> processedJobs = batchRule.syncExec(setRemovalTimeBatch); + + // then + assertProcessedJobs(setRemovalTimeBatch, processedJobs); + /* + * there is no way to filter for the historic job log of only the set historic batch removal time batch + * as a workaround: check that the historic job log contains the corresponding batch id for seed and + * monitor jobs from both batches. + */ + assertThat(setVariablesBatch.getId()).isNotNull(); + assertThat(setRemovalTimeBatch.getId()).isNotNull(); + List batchSeedJobLogs = historyService.createHistoricJobLogQuery() + .successLog() + .jobDefinitionType(BatchSeedJobHandler.TYPE) + .list(); + assertThat(batchSeedJobLogs).extracting("batchId") + .containsExactlyInAnyOrder(setVariablesBatch.getId(), setRemovalTimeBatch.getId()); + List batchMonitorJobLogs = historyService.createHistoricJobLogQuery() + .successLog() + .jobDefinitionType(BatchMonitorJobHandler.TYPE) + .list(); + assertThat(batchMonitorJobLogs).extracting("batchId") + .containsExactlyInAnyOrder(setVariablesBatch.getId(), setRemovalTimeBatch.getId()); + List batchExecutionJobLogs = historyService.createHistoricJobLogQuery() + .successLog() + .jobDefinitionType(Batch.TYPE_BATCH_SET_REMOVAL_TIME) + .list(); + assertThat(batchExecutionJobLogs).extracting("batchId").containsOnly(setRemovalTimeBatch.getId()); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_SetVariables() { + // given + testRule.deploy(getUserTaskProcess()); + ProcessInstance process = runtimeService.startProcessInstanceByKey("process"); + + Batch batch = runtimeService.setVariablesAsync(List.of(process.getId()), Variables.createVariables().putValue("foo", "bar")); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_SET_VARIABLES); + } + + @Test + @Deployment(resources = { + "org/operaton/bpm/engine/test/dmn/deployment/drdDish.dmn11.xml" + }) + public void shouldSetBatchIdOnJobAndJobLog_DecisionSetRemovalTime() { + // given + decisionService.evaluateDecisionByKey("dish-decision") + .variables( + Variables.createVariables() + .putValue("temperature", 32) + .putValue("dayType", "Weekend") + ).evaluate(); + + Batch batch = historyService.setRemovalTimeToHistoricDecisionInstances() + .absoluteRemovalTime(batchRemovalTimeRule.REMOVAL_TIME) + .byQuery(historyService.createHistoricDecisionInstanceQuery()) + .executeAsync(); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + // we expect three execution jobs, all should have the batch id + assertHistoricJobLogs(batch, Batch.TYPE_DECISION_SET_REMOVAL_TIME); + } + + @Test + @Deployment(resources = { + "org/operaton/bpm/engine/test/dmn/deployment/drdDish.dmn11.xml" + }) + public void shouldSetBatchIdOnJobAndJobLog_DeleteHistoricDecisionInstances() { + // given + decisionService.evaluateDecisionByKey("dish-decision") + .variables( + Variables.createVariables() + .putValue("temperature", 32) + .putValue("dayType", "Weekend") + ).evaluate(); + + HistoricDecisionInstanceQuery query = historyService.createHistoricDecisionInstanceQuery() + .decisionDefinitionKey("dish-decision"); + + Batch batch = historyService.deleteHistoricDecisionInstancesAsync(query, null); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_HISTORIC_DECISION_INSTANCE_DELETION); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_DeleteHistoricProcessInstances() { + // given + testRule.deploy(Bpmn.createExecutableProcess("process") + .startEvent() + .endEvent() + .done()); + runtimeService.startProcessInstanceByKey("process"); + + HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery() + .processDefinitionKey("process"); + + Batch batch = historyService.deleteHistoricProcessInstancesAsync(query, null); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_HISTORIC_PROCESS_INSTANCE_DELETION); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_DeleteProcessInstances() { + // given + testRule.deploy(getUserTaskProcess()); + ProcessInstance process = runtimeService.startProcessInstanceByKey("process"); + + Batch batch = runtimeService.deleteProcessInstancesAsync(List.of(process.getId()), null); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_PROCESS_INSTANCE_DELETION); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_MessageCorrelation() { + // given + testRule.deploy(Bpmn.createExecutableProcess("process") + .startEvent() + .intermediateCatchEvent().message("message") + .userTask() + .endEvent() + .done()); + ProcessInstance process = runtimeService.startProcessInstanceByKey("process"); + + Batch batch = runtimeService.createMessageCorrelationAsync("message") + .processInstanceIds(List.of(process.getId())) + .correlateAllAsync(); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_CORRELATE_MESSAGE); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_Migration() { + // given + ProcessDefinition sourceProcessDefinition = testRule.deployAndGetDefinition(getUserTaskProcess()); + ProcessInstance process = runtimeService.startProcessInstanceByKey("process"); + ProcessDefinition targetProcessDefinition = testRule.deployAndGetDefinition(getTwoUserTasksProcess()); + + MigrationPlan migrationPlan = runtimeService.createMigrationPlan(sourceProcessDefinition.getId(), targetProcessDefinition.getId()) + .mapEqualActivities() + .build(); + + Batch batch = runtimeService.newMigration(migrationPlan).processInstanceIds(List.of(process.getId())).executeAsync(); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_PROCESS_INSTANCE_MIGRATION); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_Modification() { + // given + testRule.deploy(getTwoUserTasksProcess()); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("process"); + + ActivityInstance tree = runtimeService.getActivityInstance(processInstance.getId()); + + // when + Batch batch = runtimeService.createProcessInstanceModification(processInstance.getId()) + .cancelActivityInstance(tree.getActivityInstances("task1")[0].getId()) + .startBeforeActivity("task2") + .executeAsync(); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_PROCESS_INSTANCE_MODIFICATION); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_ProcessSetRemovalTime() { + // given + testRule.deploy(getTwoUserTasksProcess()); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("process"); + + Batch batch = historyService.setRemovalTimeToHistoricProcessInstances() + .absoluteRemovalTime(batchRemovalTimeRule.REMOVAL_TIME) + .byIds(processInstance.getId()) + .executeAsync(); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_PROCESS_SET_REMOVAL_TIME); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_RestartProcessInstance() { + // given + testRule.deploy(getUserTaskProcess()); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("process"); + runtimeService.deleteProcessInstance(processInstance.getId(), null); + + Batch batch = runtimeService.restartProcessInstances(processInstance.getProcessDefinitionId()) + .processInstanceIds(processInstance.getId()) + .startBeforeActivity("task1") + .executeAsync(); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_PROCESS_INSTANCE_RESTART); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_SetExternalTaskRetries() { + // given + testRule.deploy(Bpmn.createExecutableProcess("process") + .startEvent() + .serviceTask().operatonExternalTask("topic") + .endEvent() + .done()); + runtimeService.startProcessInstanceByKey("process"); + + ExternalTask externalTask = externalTaskService.createExternalTaskQuery().singleResult(); + + Batch batch = externalTaskService.setRetriesAsync(List.of(externalTask.getId()), null, 5); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_SET_EXTERNAL_TASK_RETRIES); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_SetJobRetries() { + // given + testRule.deploy(getTimerProcess()); + runtimeService.startProcessInstanceByKey("process"); + + Job timerJob = managementService.createJobQuery().singleResult(); + + Batch batch = managementService.setJobRetriesAsync(List.of(timerJob.getId()), 5); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_SET_JOB_RETRIES); + } + + @Test + public void shouldSetBatchIdOnJobAndJobLog_UpdateProcessInstancesSuspendState() { + // given + testRule.deploy(getUserTaskProcess()); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("process"); + + Batch batch = runtimeService.updateProcessInstanceSuspensionState() + .byProcessInstanceIds(List.of(processInstance.getId())) + .suspendAsync(); + + // when + Map> processedJobs = batchRule.syncExec(batch); + + // then + assertProcessedJobs(batch, processedJobs); + assertHistoricJobLogs(batch, Batch.TYPE_PROCESS_INSTANCE_UPDATE_SUSPENSION_STATE); + } + + @Test + public void shouldNotSetBatchIdOnJobOrJobLog_nonBatchJob() { + // given + testRule.deploy(getTimerProcess()); + runtimeService.startProcessInstanceByKey("process"); + + Job timerJob = managementService.createJobQuery().singleResult(); + + // when + managementService.executeJob(timerJob.getId()); + + // then + List historicJobLogs = historyService.createHistoricJobLogQuery().list(); + assertThat(historicJobLogs).hasSize(2); + assertThat(historicJobLogs).extracting("batchId").containsOnlyNulls(); + } + + // HELPER + + private void assertProcessedJobs(Batch batch, Map> processedJobs) { + assertThat(processedJobs.get(BatchRule.SEED_JOB)).extracting("batchId").containsOnly(batch.getId()); + assertThat(processedJobs.get(BatchRule.EXECUTION_JOBS)).extracting("batchId").containsOnly(batch.getId()); + assertThat(processedJobs.get(BatchRule.MONITOR_JOB)).extracting("batchId").containsOnly(batch.getId()); + } + + private void assertHistoricJobLogs(Batch batch, String expectedBatchType) { + assertThat(batch.getId()).isNotNull(); + List batchSeedJobLogs = historyService.createHistoricJobLogQuery() + .successLog() + .jobDefinitionType(BatchSeedJobHandler.TYPE) + .list(); + assertThat(batchSeedJobLogs).extracting("batchId").containsOnly(batch.getId()); + List batchMonitorJobLogs = historyService.createHistoricJobLogQuery() + .successLog() + .jobDefinitionType(BatchMonitorJobHandler.TYPE) + .list(); + assertThat(batchMonitorJobLogs).extracting("batchId").containsOnly(batch.getId()); + List batchExecutionJobLogs = historyService.createHistoricJobLogQuery() + .successLog() + .jobDefinitionType(expectedBatchType) + .list(); + assertThat(batchExecutionJobLogs).extracting("batchId").containsOnly(batch.getId()); + } +} \ No newline at end of file diff --git a/engine/src/test/java/org/operaton/bpm/engine/test/util/BatchRule.java b/engine/src/test/java/org/operaton/bpm/engine/test/util/BatchRule.java index 5eaf8b332fa..02a4f9f643c 100644 --- a/engine/src/test/java/org/operaton/bpm/engine/test/util/BatchRule.java +++ b/engine/src/test/java/org/operaton/bpm/engine/test/util/BatchRule.java @@ -19,7 +19,9 @@ import static org.operaton.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl.DEFAULT_INVOCATIONS_PER_BATCH_JOB; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.operaton.bpm.engine.batch.Batch; import org.operaton.bpm.engine.batch.history.HistoricBatch; import org.operaton.bpm.engine.impl.util.ClockUtil; @@ -30,6 +32,10 @@ public class BatchRule extends TestWatcher { + public static final String SEED_JOB = "seed-job"; + public static final String MONITOR_JOB = "monitor-job"; + public static final String EXECUTION_JOBS = "execution-job"; + protected ProcessEngineRule engineRule; protected ProcessEngineTestRule engineTestRule; @@ -68,40 +74,55 @@ public void clearDatabase() { } } - public void syncExec(Batch batch) { - syncExec(batch, true); + public Map> syncExec(Batch batch) { + return syncExec(batch, true); } - public void syncExec(Batch batch, boolean isClear) { + public Map> syncExec(Batch batch, boolean isClear) { + Map> processedJobs = new HashMap<>(); + List processedSeedJobs = new ArrayList<>(); if (isClear) { batchIds.add(batch.getId()); } - executeSeedJobs(batch); + processedSeedJobs.addAll(executeSeedJobs(batch)); + processedJobs.put(SEED_JOB, processedSeedJobs); + List processedExecutionJobs = new ArrayList<>(); List jobs = getExecutionJobs(batch); while (!jobs.isEmpty()) { for (Job job : jobs) { engineRule.getManagementService().executeJob(job.getId()); + processedExecutionJobs.add(job); } jobs = getExecutionJobs(batch); } - - engineRule.getManagementService().executeJob( - getJobForDefinition(batch.getMonitorJobDefinitionId()).getId()); + processedJobs.put(EXECUTION_JOBS, processedExecutionJobs); + + List processedMonitorJobs = new ArrayList<>(); + Job monitorJob = getJobForDefinition(batch.getMonitorJobDefinitionId()); + engineRule.getManagementService().executeJob(monitorJob.getId()); + processedMonitorJobs.add(monitorJob); + processedJobs.put(MONITOR_JOB, processedMonitorJobs); + + return processedJobs; } - public void executeSeedJobs(Batch batch) { - executeSeedJobs(batch, false); + public List executeSeedJobs(Batch batch) { + return executeSeedJobs(batch, false); } - public void executeSeedJobs(Batch batch, boolean cleanUp) { + public List executeSeedJobs(Batch batch, boolean cleanUp) { + List processedJobs = new ArrayList<>(); if (cleanUp) { batchIds.add(batch.getId()); } while (getSeedJob(batch) != null) { - engineRule.getManagementService().executeJob(getSeedJob(batch).getId()); + Job seedJob = getSeedJob(batch); + engineRule.getManagementService().executeJob(seedJob.getId()); + processedJobs.add(seedJob); } + return processedJobs; } public Job getSeedJob(Batch batch) { diff --git a/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.failingSubprocessWithAsyncBeforeTask.bpmn20.xml b/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.failingSubprocessWithAsyncBeforeTask.bpmn20.xml new file mode 100644 index 00000000000..d2ddbd75867 --- /dev/null +++ b/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.failingSubprocessWithAsyncBeforeTask.bpmn20.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.subprocessWithAsyncBeforeTask.bpmn20.xml b/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.subprocessWithAsyncBeforeTask.bpmn20.xml new file mode 100644 index 00000000000..ad48668b6f5 --- /dev/null +++ b/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.subprocessWithAsyncBeforeTask.bpmn20.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.syncAfterOneTaskProcess.bpmn20.xml b/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.syncAfterOneTaskProcess.bpmn20.xml new file mode 100644 index 00000000000..562df9d6e34 --- /dev/null +++ b/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/ProcessInstanceModificationTest.syncAfterOneTaskProcess.bpmn20.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/failingProcessAfterUserTaskCreateOneIncident.bpmn20.xml b/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/failingProcessAfterUserTaskCreateOneIncident.bpmn20.xml new file mode 100644 index 00000000000..e7fb8eef394 --- /dev/null +++ b/engine/src/test/resources/org/operaton/bpm/engine/test/api/runtime/failingProcessAfterUserTaskCreateOneIncident.bpmn20.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/engine/src/test/resources/org/operaton/bpm/engine/test/history/HistoricProcessInstanceTest.testHistoricProcessInstanceQueryActivityIdInWithIncident.bpmn b/engine/src/test/resources/org/operaton/bpm/engine/test/history/HistoricProcessInstanceTest.testHistoricProcessInstanceQueryActivityIdInWithIncident.bpmn new file mode 100644 index 00000000000..4114fb0b108 --- /dev/null +++ b/engine/src/test/resources/org/operaton/bpm/engine/test/history/HistoricProcessInstanceTest.testHistoricProcessInstanceQueryActivityIdInWithIncident.bpmn @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/invoice/src/test/java/org/operaton/bpm/example/invoice/InvoiceTestCase.java b/examples/invoice/src/test/java/org/operaton/bpm/example/invoice/InvoiceTestCase.java index a89adbeea14..208226105a3 100644 --- a/examples/invoice/src/test/java/org/operaton/bpm/example/invoice/InvoiceTestCase.java +++ b/examples/invoice/src/test/java/org/operaton/bpm/example/invoice/InvoiceTestCase.java @@ -16,27 +16,40 @@ */ package org.operaton.bpm.example.invoice; -import static org.operaton.bpm.engine.variable.Variables.fileValue; - -import java.io.InputStream; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.operaton.bpm.engine.ManagementService; +import org.operaton.bpm.engine.ProcessEngine; +import org.operaton.bpm.engine.RuntimeService; +import org.operaton.bpm.engine.TaskService; import org.operaton.bpm.engine.runtime.Job; import org.operaton.bpm.engine.runtime.ProcessInstance; import org.operaton.bpm.engine.task.IdentityLink; import org.operaton.bpm.engine.task.Task; import org.operaton.bpm.engine.test.Deployment; -import org.operaton.bpm.engine.test.ProcessEngineTestCase; +import org.operaton.bpm.engine.test.junit5.ProcessEngineExtension; import org.operaton.bpm.engine.variable.VariableMap; import org.operaton.bpm.engine.variable.Variables; -public class InvoiceTestCase extends ProcessEngineTestCase { +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; - @Deployment(resources= {"invoice.v1.bpmn", "invoiceBusinessDecisions.dmn"}) - public void testHappyPathV1() { +import static org.junit.jupiter.api.Assertions.*; +import static org.operaton.bpm.engine.impl.test.ProcessEngineAssert.assertProcessEnded; +import static org.operaton.bpm.engine.variable.Variables.fileValue; + +@ExtendWith(ProcessEngineExtension.class) +public class InvoiceTestCase { + ProcessEngine processEngine; + RuntimeService runtimeService; + TaskService taskService; + ManagementService managementService; + @Deployment(resources = {"invoice.v1.bpmn", "invoiceBusinessDecisions.dmn"}) + @Test + public void testHappyPathV1() { InputStream invoiceInputStream = InvoiceProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf"); VariableMap variables = Variables.createVariables() .putValue("creditor", "Great Pizza for Everyone Inc.") @@ -75,11 +88,12 @@ public void testHappyPathV1() { assertNotNull(archiveInvoiceJob); managementService.executeJob(archiveInvoiceJob.getId()); - assertProcessEnded(pi.getId()); + assertProcessEnded(processEngine, pi.getId()); } - @Deployment(resources= {"invoice.v2.bpmn", "invoiceBusinessDecisions.dmn"}) - public void testHappyPathV2() { + @Deployment(resources = {"invoice.v2.bpmn", "invoiceBusinessDecisions.dmn"}) + @Test + public void testHappyPathV2() { InputStream invoiceInputStream = InvoiceProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf"); VariableMap variables = Variables.createVariables() .putValue("creditor", "Great Pizza for Everyone Inc.") @@ -118,11 +132,12 @@ public void testHappyPathV2() { assertNotNull(archiveInvoiceJob); managementService.executeJob(archiveInvoiceJob.getId()); - assertProcessEnded(pi.getId()); + assertProcessEnded(processEngine, pi.getId()); } - @Deployment(resources= {"invoice.v2.bpmn", "invoiceBusinessDecisions.dmn"}) - public void testApproveInvoiceAssignment() { + @Deployment(resources = {"invoice.v2.bpmn", "invoiceBusinessDecisions.dmn"}) + @Test + public void testApproveInvoiceAssignment() { InputStream invoiceInputStream = InvoiceProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf"); VariableMap variables = Variables.createVariables() @@ -165,8 +180,9 @@ public void testApproveInvoiceAssignment() { assertEquals("mary", taskService.getVariable(task.getId(), "approver")); } - @Deployment(resources= {"invoice.v2.bpmn", "reviewInvoice.bpmn", "invoiceBusinessDecisions.dmn"}) - public void testNonSuccessfulPath() { + @Deployment(resources = {"invoice.v2.bpmn", "reviewInvoice.bpmn", "invoiceBusinessDecisions.dmn"}) + @Test + public void testNonSuccessfulPath() { InputStream invoiceInputStream = InvoiceProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf"); VariableMap variables = Variables.createVariables() .putValue("creditor", "Great Pizza for Everyone Inc.") @@ -210,9 +226,11 @@ public void testNonSuccessfulPath() { variables.put("clarified", Boolean.FALSE); taskService.complete(task.getId(), variables); - assertProcessEnded(task.getProcessInstanceId()); - assertProcessEnded(pi.getId()); + assertProcessEnded(processEngine, task.getProcessInstanceId()); + assertProcessEnded(processEngine, pi.getId()); } } + + diff --git a/examples/pom.xml b/examples/pom.xml index 01ac4583376..bf4675fcadd 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -33,12 +33,6 @@ provided
- - junit - junit - test - - com.h2database h2 @@ -57,6 +51,12 @@ test + + org.operaton.bpm + operaton-bpm-junit5 + test + + diff --git a/internal-dependencies/pom.xml b/internal-dependencies/pom.xml index c60d3432358..b30ae29500a 100644 --- a/internal-dependencies/pom.xml +++ b/internal-dependencies/pom.xml @@ -15,10 +15,6 @@ Operaton core internal bill of material for dependencies - - 5.11.3 - - @@ -340,7 +336,7 @@ org.apache.tomcat catalina - 6.0.37 + 6.0.53 diff --git a/parent/pom.xml b/parent/pom.xml index c32246077d4..02e8630b2cd 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -18,9 +18,9 @@ - 3.8.5 - 5.3.36 - 6.1.8 + 3.15.0 + 5.3.39 + 6.1.13 3.3.5 3.15.6.Final 2.34 @@ -43,6 +43,7 @@ 4.0.5 4.0.2 4.5.14 + 5.3 1.7.26 1.2.11 @@ -64,7 +65,7 @@ 18.0.4.Final 9.0.90 - 10.1.25 + 10.1.30 1.1.10.Final 2.2.2 @@ -76,6 +77,7 @@ 20.14.0 10.7.0 + 5.11.3 diff --git a/pom.xml b/pom.xml index 177eb6d547b..14710023bbd 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 17 operaton https://sonarcloud.io - **/target/jacoco/jacoco.xml + **/target/jacoco/jacoco.xml diff --git a/quarkus-extension/README.md b/quarkus-extension/README.md index 2681dd522f1..96de365277a 100644 --- a/quarkus-extension/README.md +++ b/quarkus-extension/README.md @@ -26,18 +26,18 @@ can look like the following: ```properties # process engine configuration -quarkus.operaton.cmmn-enabled=false -quarkus.operaton.dmn-enabled=false -quarkus.operaton.history=none +quarkus.operaton.generic-config.cmmn-enabled=false +quarkus.operaton.generic-config.dmn-enabled=false +quarkus.operaton.generic-config.history=none # job executor configuration quarkus.operaton.job-executor.thread-pool.max-pool-size=12 quarkus.operaton.job-executor.thread-pool.queue-size=5 -quarkus.operaton.job-executor.max-jobs-per-acquisition=5 -quarkus.operaton.job-executor.lock-time-in-millis=500000 -quarkus.operaton.job-executor.wait-time-in-millis=7000 -quarkus.operaton.job-executor.max-wait=65000 -quarkus.operaton.job-executor.backoff-time-in-millis=5 +quarkus.operaton.job-executor.generic-config.max-jobs-per-acquisition=5 +quarkus.operaton.job-executor.generic-config.lock-time-in-millis=500000 +quarkus.operaton.job-executor.generic-config.wait-time-in-millis=7000 +quarkus.operaton.job-executor.generic-config.max-wait=65000 +quarkus.operaton.job-executor.generic-config.backoff-time-in-millis=5 # custom data source configuration and selection quarkus.datasource.my-datasource.db-kind=h2 @@ -80,4 +80,4 @@ Bytecode: 0000000: 2ab7 0007 2abb 000c 59b7 000e b500 0f2a 0000010: 03b5 0013 2abb 0017 59b7 0019 b500 1a2a 0000020: 2bb5 001e b1``` - \ No newline at end of file + diff --git a/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineConfigFileTest.java b/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineConfigFileTest.java index 2d201a4bb3e..14cc0c57733 100644 --- a/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineConfigFileTest.java +++ b/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineConfigFileTest.java @@ -67,10 +67,10 @@ public void shouldLoadAllConfigProperties() throws SQLException { assertThat(jobExecutor.getMaxWait()).isEqualTo(65000); assertThat(jobExecutor.getBackoffTimeInMillis()).isEqualTo(5); // assert correct thread pool config - assertThat(config.jobExecutor.threadPool.maxPoolSize).isEqualTo(12); - assertThat(config.jobExecutor.threadPool.queueSize).isEqualTo(5); + assertThat(config.jobExecutor().threadPool().maxPoolSize()).isEqualTo(12); + assertThat(config.jobExecutor().threadPool().queueSize()).isEqualTo(5); // assert correct datasource - assertThat(config.datasource).hasValue("operaton"); + assertThat(config.datasource()).hasValue("operaton"); assertThat(configuration.getDataSource().getConnection()).asString().contains("h2:mem:operaton"); } } \ No newline at end of file diff --git a/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineConfigurationConfigTest.java b/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineConfigurationConfigTest.java index 9fcde2bebfd..806775351b7 100644 --- a/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineConfigurationConfigTest.java +++ b/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineConfigurationConfigTest.java @@ -49,9 +49,9 @@ public void shouldLoadProcessEngineConfigurationProperties() { // given a custom application.properties file // then - assertThat(config.genericConfig.get("cmmn-enabled")).isEqualTo("false"); - assertThat(config.genericConfig.get("dmn-enabled")).isEqualTo("false"); - assertThat(config.genericConfig.get("history")).isEqualTo("none"); + assertThat(config.genericConfig().get("cmmn-enabled")).isEqualTo("false"); + assertThat(config.genericConfig().get("dmn-enabled")).isEqualTo("false"); + assertThat(config.genericConfig().get("history")).isEqualTo("none"); } @Test diff --git a/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineJobExecutorConfigTest.java b/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineJobExecutorConfigTest.java index bd99ec2bea2..6b44ab75cb2 100644 --- a/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineJobExecutorConfigTest.java +++ b/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineJobExecutorConfigTest.java @@ -44,8 +44,8 @@ public void shouldLoadJobExecutorThreadPoolProperties() { // given a custom application.properties file // then - assertThat(config.jobExecutor.threadPool.maxPoolSize).isEqualTo(12); - assertThat(config.jobExecutor.threadPool.queueSize).isEqualTo(5); + assertThat(config.jobExecutor().threadPool().maxPoolSize()).isEqualTo(12); + assertThat(config.jobExecutor().threadPool().queueSize()).isEqualTo(5); } @Test @@ -53,13 +53,13 @@ public void shouldLoadJobAcquisitionProperties() { // given a custom application.properties file // then - assertThat(config.jobExecutor.genericConfig.get("max-jobs-per-acquisition")).isEqualTo("5"); - assertThat(config.jobExecutor.genericConfig.get("lock-time-in-millis")).isEqualTo("500000"); - assertThat(config.jobExecutor.genericConfig.get("wait-time-in-millis")).isEqualTo("7000"); - assertThat(config.jobExecutor.genericConfig.get("max-wait")).isEqualTo("65000"); - assertThat(config.jobExecutor.genericConfig.get("backoff-time-in-millis")).isEqualTo("5"); - assertThat(config.jobExecutor.genericConfig.get("max-backoff")).isEqualTo("5"); - assertThat(config.jobExecutor.genericConfig.get("backoff-decrease-threshold")).isEqualTo("120"); - assertThat(config.jobExecutor.genericConfig.get("wait-increase-factor")).isEqualTo("3"); + assertThat(config.jobExecutor().genericConfig().get("max-jobs-per-acquisition")).isEqualTo("5"); + assertThat(config.jobExecutor().genericConfig().get("lock-time-in-millis")).isEqualTo("500000"); + assertThat(config.jobExecutor().genericConfig().get("wait-time-in-millis")).isEqualTo("7000"); + assertThat(config.jobExecutor().genericConfig().get("max-wait")).isEqualTo("65000"); + assertThat(config.jobExecutor().genericConfig().get("backoff-time-in-millis")).isEqualTo("5"); + assertThat(config.jobExecutor().genericConfig().get("max-backoff")).isEqualTo("5"); + assertThat(config.jobExecutor().genericConfig().get("backoff-decrease-threshold")).isEqualTo("120"); + assertThat(config.jobExecutor().genericConfig().get("wait-increase-factor")).isEqualTo("3"); } } diff --git a/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineProgrammaticAndConfigFileTest.java b/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineProgrammaticAndConfigFileTest.java index 4cf8c72f87d..ab0a29dd672 100644 --- a/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineProgrammaticAndConfigFileTest.java +++ b/quarkus-extension/engine/deployment/src/test/java/org/operaton/bpm/quarkus/engine/test/config/OperatonEngineProgrammaticAndConfigFileTest.java @@ -88,10 +88,10 @@ public void shouldUseProvidedConfigurationAndConfigProperties() throws SQLExcept assertThat(jobExecutor.getMaxWait()).isEqualTo(65000); assertThat(jobExecutor.getBackoffTimeInMillis()).isEqualTo(5); // assert correct thread pool config - assertThat(config.jobExecutor.threadPool.maxPoolSize).isEqualTo(12); - assertThat(config.jobExecutor.threadPool.queueSize).isEqualTo(5); + assertThat(config.jobExecutor().threadPool().maxPoolSize()).isEqualTo(12); + assertThat(config.jobExecutor().threadPool().queueSize()).isEqualTo(5); // assert correct datasource - assertThat(config.datasource).hasValue("operaton"); + assertThat(config.datasource()).hasValue("operaton"); assertThat(configuration.getDataSource().getConnection()).asString().contains("h2:mem:operaton"); } } \ No newline at end of file diff --git a/quarkus-extension/engine/deployment/src/test/resources/application.properties b/quarkus-extension/engine/deployment/src/test/resources/application.properties index c4d90ee12a6..22ce7663147 100644 --- a/quarkus-extension/engine/deployment/src/test/resources/application.properties +++ b/quarkus-extension/engine/deployment/src/test/resources/application.properties @@ -1,2 +1,2 @@ quarkus.datasource.jdbc.url=jdbc:h2:mem:operaton;TRACE_LEVEL_FILE=0;DB_CLOSE_ON_EXIT=FALSE -quarkus.operaton.enforce-history-time-to-live=false \ No newline at end of file +quarkus.operaton.generic-config.enforce-history-time-to-live=false \ No newline at end of file diff --git a/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/job-executor-application.properties b/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/job-executor-application.properties index 341a2533df9..b6f7df1bf20 100644 --- a/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/job-executor-application.properties +++ b/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/job-executor-application.properties @@ -1,15 +1,15 @@ quarkus.operaton.job-executor.thread-pool.max-pool-size=12 quarkus.operaton.job-executor.thread-pool.queue-size=5 -quarkus.operaton.job-executor.max-jobs-per-acquisition=5 -quarkus.operaton.job-executor.lock-time-in-millis=500000 -quarkus.operaton.job-executor.wait-time-in-millis=7000 -quarkus.operaton.job-executor.max-wait=65000 -quarkus.operaton.job-executor.backoff-time-in-millis=5 -quarkus.operaton.job-executor.max-backoff=5 -quarkus.operaton.job-executor.backoff-decrease-threshold=120 -quarkus.operaton.job-executor.wait-increase-factor=3 +quarkus.operaton.job-executor.generic-config.max-jobs-per-acquisition=5 +quarkus.operaton.job-executor.generic-config.lock-time-in-millis=500000 +quarkus.operaton.job-executor.generic-config.wait-time-in-millis=7000 +quarkus.operaton.job-executor.generic-config.max-wait=65000 +quarkus.operaton.job-executor.generic-config.backoff-time-in-millis=5 +quarkus.operaton.job-executor.generic-config.max-backoff=5 +quarkus.operaton.job-executor.generic-config.backoff-decrease-threshold=120 +quarkus.operaton.job-executor.generic-config.wait-increase-factor=3 quarkus.datasource.jdbc.url=jdbc:h2:mem:operaton;TRACE_LEVEL_FILE=0;DB_CLOSE_ON_EXIT=FALSE -quarkus.operaton.enforce-history-time-to-live=false \ No newline at end of file +quarkus.operaton.generic-config.enforce-history-time-to-live=false \ No newline at end of file diff --git a/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/mixed-application.properties b/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/mixed-application.properties index 363710ce92b..77829f68b26 100644 --- a/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/mixed-application.properties +++ b/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/mixed-application.properties @@ -1,16 +1,16 @@ -quarkus.operaton.cmmn-enabled=false -quarkus.operaton.dmn-enabled=false -quarkus.operaton.history=none -quarkus.operaton.enforce-history-time-to-live=false +quarkus.operaton.generic-config.cmmn-enabled=false +quarkus.operaton.generic-config.dmn-enabled=false +quarkus.operaton.generic-config.history=none +quarkus.operaton.generic-config.enforce-history-time-to-live=false quarkus.operaton.job-executor.thread-pool.max-pool-size=12 quarkus.operaton.job-executor.thread-pool.queue-size=5 -quarkus.operaton.job-executor.max-jobs-per-acquisition=5 -quarkus.operaton.job-executor.lock-time-in-millis=500000 -quarkus.operaton.job-executor.wait-time-in-millis=7000 -quarkus.operaton.job-executor.max-wait=65000 -quarkus.operaton.job-executor.backoff-time-in-millis=5 +quarkus.operaton.job-executor.generic-config.max-jobs-per-acquisition=5 +quarkus.operaton.job-executor.generic-config.lock-time-in-millis=500000 +quarkus.operaton.job-executor.generic-config.wait-time-in-millis=7000 +quarkus.operaton.job-executor.generic-config.max-wait=65000 +quarkus.operaton.job-executor.generic-config.backoff-time-in-millis=5 quarkus.datasource.operaton.db-kind=h2 quarkus.datasource.operaton.username=operaton diff --git a/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/process-engine-config-application.properties b/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/process-engine-config-application.properties index f288bf295e2..1662729a065 100644 --- a/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/process-engine-config-application.properties +++ b/quarkus-extension/engine/deployment/src/test/resources/org/operaton/bpm/quarkus/engine/test/config/process-engine-config-application.properties @@ -1,6 +1,6 @@ -quarkus.operaton.cmmn-enabled=false -quarkus.operaton.dmn-enabled=false -quarkus.operaton.history=none -quarkus.operaton.enforce-history-time-to-live=false +quarkus.operaton.generic-config.cmmn-enabled=false +quarkus.operaton.generic-config.dmn-enabled=false +quarkus.operaton.generic-config.history=none +quarkus.operaton.generic-config.enforce-history-time-to-live=false quarkus.datasource.jdbc.url=jdbc:h2:mem:operaton;TRACE_LEVEL_FILE=0;DB_CLOSE_ON_EXIT=FALSE \ No newline at end of file diff --git a/quarkus-extension/engine/qa/src/test/resources/application.properties b/quarkus-extension/engine/qa/src/test/resources/application.properties index 8bdeecb7689..3abfea8fd1f 100644 --- a/quarkus-extension/engine/qa/src/test/resources/application.properties +++ b/quarkus-extension/engine/qa/src/test/resources/application.properties @@ -6,4 +6,4 @@ quarkus.log.category."org.operaton".level=INFO quarkus.datasource.jdbc.url=jdbc:h2:mem:operaton;TRACE_LEVEL_FILE=0;DB_CLOSE_ON_EXIT=FALSE -quarkus.operaton.enforce-history-time-to-live=false \ No newline at end of file +quarkus.operaton.generic-config.enforce-history-time-to-live=false \ No newline at end of file diff --git a/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/OperatonEngineConfig.java b/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/OperatonEngineConfig.java index 00fead4723a..e3ef6311874 100644 --- a/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/OperatonEngineConfig.java +++ b/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/OperatonEngineConfig.java @@ -16,22 +16,21 @@ */ package org.operaton.bpm.quarkus.engine.extension; -import java.util.Map; -import java.util.Optional; - -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import java.util.Map; +import java.util.Optional; -@ConfigRoot(phase = ConfigPhase.RUN_TIME, name = "operaton") -public class OperatonEngineConfig { +@ConfigMapping(prefix = "quarkus.operaton") +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +public interface OperatonEngineConfig { /** * The Operaton ProcessEngineConfiguration properties. For more details, * @see Process Engine Configuration Properties. */ - @ConfigItem(name = ConfigItem.PARENT) - public Map genericConfig; + Map genericConfig(); /** * The Operaton JobExecutor config. It provides available job acquisition thread configuration @@ -39,13 +38,11 @@ public class OperatonEngineConfig { * * The JobExecutor is responsible for running Operaton jobs. */ - @ConfigItem - public OperatonJobExecutorConfig jobExecutor; + OperatonJobExecutorConfig jobExecutor(); /** * Select a datasource by name or the default datasource is used. */ - @ConfigItem - public Optional datasource; + Optional datasource(); } \ No newline at end of file diff --git a/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/OperatonJobExecutorConfig.java b/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/OperatonJobExecutorConfig.java index b9d7f5a6bf3..4693588ae6a 100644 --- a/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/OperatonJobExecutorConfig.java +++ b/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/OperatonJobExecutorConfig.java @@ -16,42 +16,36 @@ */ package org.operaton.bpm.quarkus.engine.extension; +import io.smallrye.config.WithDefault; import java.util.Map; -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; - -@ConfigGroup -public class OperatonJobExecutorConfig { +public interface OperatonJobExecutorConfig { /** * The Operaton JobExecutor configuration properties. For more details, * @see Job-Acquisition Configuration Properties */ - @ConfigItem(name = ConfigItem.PARENT) - public Map genericConfig; + Map genericConfig(); /** * The Operaton JobExecutor thread pool config. This thread pool is responsible for running * Operaton jobs. */ - @ConfigItem - public ThreadPoolConfig threadPool; + ThreadPoolConfig threadPool(); - @ConfigGroup - public static class ThreadPoolConfig { + interface ThreadPoolConfig { /** * Sets the maximum number of threads that can be present in the Quarkus-managed * thread pool for the Operaton JobExecutor. The default value is 10. */ - @ConfigItem(defaultValue = "10") - public int maxPoolSize; + @WithDefault("10") + int maxPoolSize(); /** * Sets the size of the Quarkus-managed JobExecutor queue. The default value is 3. */ - @ConfigItem(defaultValue = "3") - public int queueSize; + @WithDefault("3") + int queueSize(); } } \ No newline at end of file diff --git a/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/impl/OperatonEngineRecorder.java b/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/impl/OperatonEngineRecorder.java index 31a8e6200e1..4a07c44cd28 100644 --- a/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/impl/OperatonEngineRecorder.java +++ b/quarkus-extension/engine/runtime/src/main/java/org/operaton/bpm/quarkus/engine/extension/impl/OperatonEngineRecorder.java @@ -59,10 +59,10 @@ public RuntimeValue createProcessEngineConfigura beanContainer); // apply properties from config before any other configuration. - PropertyHelper.applyProperties(configuration, config.genericConfig, PropertyHelper.KEBAB_CASE); + PropertyHelper.applyProperties(configuration, config.genericConfig(), PropertyHelper.KEBAB_CASE); if (configuration.getDataSource() == null) { - String datasource = config.datasource.orElse(DEFAULT_DATASOURCE_NAME); + String datasource = config.datasource().orElse(DEFAULT_DATASOURCE_NAME); configuration.setDataSource(DataSources.fromName(datasource)); } @@ -138,8 +138,8 @@ public void registerShutdownTask(ShutdownContext shutdownContext, protected void configureJobExecutor(ProcessEngineConfigurationImpl configuration, OperatonEngineConfig config) { - int maxPoolSize = config.jobExecutor.threadPool.maxPoolSize; - int queueSize = config.jobExecutor.threadPool.queueSize; + int maxPoolSize = config.jobExecutor().threadPool().maxPoolSize(); + int queueSize = config.jobExecutor().threadPool().queueSize(); // create a non-bean ManagedExecutor instance. This instance // uses it's own Executor/thread pool. @@ -152,7 +152,7 @@ protected void configureJobExecutor(ProcessEngineConfigurationImpl configuration // apply job executor configuration properties PropertyHelper - .applyProperties(quarkusJobExecutor, config.jobExecutor.genericConfig, PropertyHelper.KEBAB_CASE); + .applyProperties(quarkusJobExecutor, config.jobExecutor().genericConfig(), PropertyHelper.KEBAB_CASE); configuration.setJobExecutor(quarkusJobExecutor); } diff --git a/quarkus-extension/pom.xml b/quarkus-extension/pom.xml index f253fcdec17..98387496432 100644 --- a/quarkus-extension/pom.xml +++ b/quarkus-extension/pom.xml @@ -18,6 +18,13 @@ + + org.junit + junit-bom + ${version.junit5} + pom + import + io.quarkus quarkus-bom diff --git a/spring-boot-starter/pom.xml b/spring-boot-starter/pom.xml index cd37eb626c8..d1539c57697 100644 --- a/spring-boot-starter/pom.xml +++ b/spring-boot-starter/pom.xml @@ -16,6 +16,13 @@ + + org.junit + junit-bom + ${version.junit5} + pom + import + org.springframework.boot @@ -36,6 +43,7 @@ starter starter-rest + starter-security starter-test starter-client/spring starter-client/spring-boot @@ -72,6 +80,7 @@ starter-qa starter starter-rest + starter-security starter-client/spring-boot starter-webapp-core diff --git a/spring-boot-starter/starter-security/pom.xml b/spring-boot-starter/starter-security/pom.xml new file mode 100644 index 00000000000..3b97451a353 --- /dev/null +++ b/spring-boot-starter/starter-security/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + + org.operaton.bpm.springboot.project + operaton-bpm-spring-boot-starter-root + 1.0.0-beta-2 + + + org.operaton.bpm.springboot + operaton-bpm-spring-boot-starter-security + Operaton Platform - Spring Boot Starter - Spring Security + + + + ${project.groupId} + operaton-bpm-spring-boot-starter + ${project.version} + provided + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + + ${project.groupId} + operaton-bpm-spring-boot-starter-rest + ${project.version} + test + + + operaton-bpm-spring-boot-starter-test + ${project.groupId} + ${project.version} + test + + + org.apache.httpcomponents.client5 + httpclient5 + ${version.httpclient5} + test + + + com.h2database + h2 + test + + + + diff --git a/spring-boot-starter/starter-security/src/test/java/my/own/custom/spring/boot/project/SampleApplication.java b/spring-boot-starter/starter-security/src/test/java/my/own/custom/spring/boot/project/SampleApplication.java new file mode 100644 index 00000000000..6e670d23149 --- /dev/null +++ b/spring-boot-starter/starter-security/src/test/java/my/own/custom/spring/boot/project/SampleApplication.java @@ -0,0 +1,47 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package my.own.custom.spring.boot.project; + +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; + +@SpringBootConfiguration +@EnableAutoConfiguration +public class SampleApplication { + + public static void main(String... args) { + SpringApplication.run(SampleApplication.class, args); + } + + @Bean + public TestRestTemplate restTemplate(RestTemplateBuilder builder) { + builder.requestFactory(() -> { + var factory = new HttpComponentsClientHttpRequestFactory(); + var httpClient = HttpClientBuilder.create().disableRedirectHandling().build(); + factory.setHttpClient(httpClient); + return factory; + }); + return new TestRestTemplate(builder); + } + +} diff --git a/spring-boot-starter/starter-security/src/test/java/my/own/custom/spring/boot/project/SamplePermitAllApplication.java b/spring-boot-starter/starter-security/src/test/java/my/own/custom/spring/boot/project/SamplePermitAllApplication.java new file mode 100644 index 00000000000..b18d8c194d4 --- /dev/null +++ b/spring-boot-starter/starter-security/src/test/java/my/own/custom/spring/boot/project/SamplePermitAllApplication.java @@ -0,0 +1,43 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package my.own.custom.spring.boot.project; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.SecurityFilterChain; + +@SpringBootConfiguration +@EnableAutoConfiguration +public class SamplePermitAllApplication { + + public static void main(String... args) { + SpringApplication.run(SamplePermitAllApplication.class, args); + } + + @Bean + public SecurityFilterChain filterChainPermitAll(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(customizer -> customizer.anyRequest().permitAll()) + .cors(AbstractHttpConfigurer::disable) + .csrf(AbstractHttpConfigurer::disable); + return http.build(); + } + +} diff --git a/spring-boot-starter/starter-security/src/test/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSampleApplicationTest.java b/spring-boot-starter/starter-security/src/test/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSampleApplicationTest.java new file mode 100644 index 00000000000..09fa9e8df4c --- /dev/null +++ b/spring-boot-starter/starter-security/src/test/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSampleApplicationTest.java @@ -0,0 +1,62 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.operaton.bpm.spring.boot.starter.security; + +import jakarta.annotation.PostConstruct; +import my.own.custom.spring.boot.project.SampleApplication; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SampleApplication.class, webEnvironment = RANDOM_PORT) +public class OperatonBpmSampleApplicationTest { + + private String baseUrl; + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate testRestTemplate; + + @PostConstruct + public void postConstruct() { + baseUrl = "http://localhost:" + port; + } + + @Test + public void restApiIsAvailable() { + ResponseEntity entity = testRestTemplate.getForEntity(baseUrl + "/engine-rest/engine/", String.class); + // default Spring Security filter chain config redirects to /login + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND); + assertThat(entity.getHeaders()).contains(entry(HttpHeaders.LOCATION, List.of(baseUrl + "/login"))); + } +} diff --git a/spring-boot-starter/starter-security/src/test/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSamplePermitAllApplicationTest.java b/spring-boot-starter/starter-security/src/test/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSamplePermitAllApplicationTest.java new file mode 100644 index 00000000000..c0335954f78 --- /dev/null +++ b/spring-boot-starter/starter-security/src/test/java/org/operaton/bpm/spring/boot/starter/security/OperatonBpmSamplePermitAllApplicationTest.java @@ -0,0 +1,47 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.operaton.bpm.spring.boot.starter.security; + +import my.own.custom.spring.boot.project.SamplePermitAllApplication; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = SamplePermitAllApplication.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT +) +public class OperatonBpmSamplePermitAllApplicationTest { + + @Autowired + private TestRestTemplate testRestTemplate; + + @Test + public void restApiIsAvailable() { + ResponseEntity entity = testRestTemplate.getForEntity("/engine-rest/engine/", String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(entity.getBody()).isEqualTo("[{\"name\":\"default\"}]"); + } +} diff --git a/spring-boot-starter/starter-security/src/test/resources/logback-test.xml b/spring-boot-starter/starter-security/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..559f9d5c889 --- /dev/null +++ b/spring-boot-starter/starter-security/src/test/resources/logback-test.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test-utils/assert/pom.xml b/test-utils/assert/pom.xml index 4b38999ff00..b2cf693a91f 100644 --- a/test-utils/assert/pom.xml +++ b/test-utils/assert/pom.xml @@ -14,6 +14,13 @@ + + org.junit + junit-bom + ${version.junit5} + pom + import +