From 65bd7ab6150417d8b52c6c70639450a0ed221dda Mon Sep 17 00:00:00 2001 From: Joram Barrez Date: Mon, 1 Jun 2020 11:47:15 +0200 Subject: [PATCH] Cmmn: fix plan item java delegate trigger not possible --- ...temDelegateExpressionActivityBehavior.java | 28 +++++- .../impl/delegate/CmmnClassDelegate.java | 20 +++- .../cmmn/test/runtime/ServiceTaskTest.java | 67 ++++++++++--- ...t.testCmmnTriggerableActivityBehavior.cmmn | 20 ++++ ...ingPlanItemJavaDelegateExpressionTest.java | 96 +++++++++++++++++++ .../spring/test/el/SpringBeanTest-context.xml | 3 + ...bleActivityBehaviorDelegateExpression.cmmn | 20 ++++ ...st.testPlanItemJavaDelegateExpression.cmmn | 20 ++++ 8 files changed, 256 insertions(+), 18 deletions(-) create mode 100644 modules/flowable-cmmn-engine/src/test/resources/org/flowable/cmmn/test/runtime/ServiceTaskTest.testCmmnTriggerableActivityBehavior.cmmn create mode 100644 modules/flowable-cmmn-spring/src/test/java/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.java create mode 100644 modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.testCmmnTriggerableActivityBehaviorDelegateExpression.cmmn create mode 100644 modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.testPlanItemJavaDelegateExpression.cmmn diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/PlanItemDelegateExpressionActivityBehavior.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/PlanItemDelegateExpressionActivityBehavior.java index 76ea49df7f5..b93d13e6678 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/PlanItemDelegateExpressionActivityBehavior.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/PlanItemDelegateExpressionActivityBehavior.java @@ -16,7 +16,8 @@ import org.flowable.cmmn.api.delegate.PlanItemJavaDelegate; import org.flowable.cmmn.engine.impl.behavior.CmmnActivityBehavior; -import org.flowable.cmmn.engine.impl.behavior.CoreCmmnActivityBehavior; +import org.flowable.cmmn.engine.impl.behavior.CmmnTriggerableActivityBehavior; +import org.flowable.cmmn.engine.impl.behavior.CoreCmmnTriggerableActivityBehavior; import org.flowable.cmmn.engine.impl.behavior.PlanItemActivityBehavior; import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; import org.flowable.cmmn.engine.impl.util.CommandContextUtil; @@ -34,7 +35,7 @@ * @author Josh Long * @author Tijs Rademakers */ -public class PlanItemDelegateExpressionActivityBehavior extends CoreCmmnActivityBehavior { +public class PlanItemDelegateExpressionActivityBehavior extends CoreCmmnTriggerableActivityBehavior { protected String expression; protected List fieldExtensions; @@ -52,13 +53,16 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt if (delegate instanceof PlanItemActivityBehavior) { ((PlanItemActivityBehavior) delegate).execute(planItemInstanceEntity); + } else if (delegate instanceof CmmnActivityBehavior) { // includes CmmnTriggerableActivityBehavior + ((CmmnActivityBehavior) delegate).execute(planItemInstanceEntity); + } else if (delegate instanceof PlanItemJavaDelegate) { PlanItemJavaDelegateActivityBehavior behavior = new PlanItemJavaDelegateActivityBehavior((PlanItemJavaDelegate) delegate); behavior.execute(planItemInstanceEntity); } else { throw new FlowableIllegalArgumentException("Delegate expression " + expression + " did neither resolve to an implementation of " + - PlanItemActivityBehavior.class + " nor " + PlanItemJavaDelegate.class); + PlanItemActivityBehavior.class + ", " + CmmnActivityBehavior.class + " nor " + PlanItemJavaDelegate.class); } } catch (Exception exc) { @@ -66,4 +70,22 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt } } + @Override + public void trigger(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) { + try { + Expression expressionObject = CommandContextUtil.getCmmnEngineConfiguration(commandContext).getExpressionManager().createExpression(expression); + Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expressionObject, planItemInstanceEntity, fieldExtensions); + if (delegate instanceof CmmnTriggerableActivityBehavior) { // includes CmmnTriggerableActivityBehavior + ((CmmnTriggerableActivityBehavior) delegate).trigger(planItemInstanceEntity); + + } else { + throw new FlowableIllegalArgumentException("Delegate expression " + expression + " did neither resolve to an implementation of " + + CmmnTriggerableActivityBehavior.class); + } + + } catch (Exception exc) { + throw new FlowableException(exc.getMessage(), exc); + } + } + } diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java index cb7e1fe39c4..dc7df174976 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java @@ -20,6 +20,7 @@ import org.flowable.cmmn.api.listener.PlanItemInstanceLifecycleListener; import org.flowable.cmmn.api.runtime.CaseInstance; import org.flowable.cmmn.engine.impl.behavior.CmmnActivityBehavior; +import org.flowable.cmmn.engine.impl.behavior.CmmnTriggerableActivityBehavior; import org.flowable.cmmn.engine.impl.behavior.impl.PlanItemJavaDelegateActivityBehavior; import org.flowable.cmmn.engine.impl.util.CommandContextUtil; import org.flowable.cmmn.model.FieldExtension; @@ -32,7 +33,7 @@ /** * @author Joram Barrez */ -public class CmmnClassDelegate implements CmmnActivityBehavior, TaskListener, PlanItemInstanceLifecycleListener, CaseInstanceLifecycleListener { +public class CmmnClassDelegate implements CmmnTriggerableActivityBehavior, TaskListener, PlanItemInstanceLifecycleListener, CaseInstanceLifecycleListener { protected String sourceState; protected String targetState; @@ -53,6 +54,20 @@ public void execute(DelegatePlanItemInstance planItemInstance) { activityBehaviorInstance.execute(planItemInstance); } + @Override + public void trigger(DelegatePlanItemInstance planItemInstance) { + if (activityBehaviorInstance == null) { + activityBehaviorInstance = getCmmnActivityBehavior(className); + } + + if (!(activityBehaviorInstance instanceof CmmnTriggerableActivityBehavior)) { + throw new FlowableIllegalArgumentException(className + " does not implement the " + + CmmnTriggerableActivityBehavior.class + " interface"); + } + + ((CmmnTriggerableActivityBehavior) activityBehaviorInstance).trigger(planItemInstance); + } + protected CmmnActivityBehavior getCmmnActivityBehavior(String className) { Object instance = instantiate(className); applyFieldExtensions(fieldExtensions, instance, false); @@ -60,6 +75,9 @@ protected CmmnActivityBehavior getCmmnActivityBehavior(String className) { if (instance instanceof PlanItemJavaDelegate) { return new PlanItemJavaDelegateActivityBehavior((PlanItemJavaDelegate) instance); + } else if (instance instanceof CmmnTriggerableActivityBehavior) { + return (CmmnTriggerableActivityBehavior) instance; + } else if (instance instanceof CmmnActivityBehavior) { return (CmmnActivityBehavior) instance; diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/runtime/ServiceTaskTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/runtime/ServiceTaskTest.java index 231d0df0b7f..100e4337e67 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/runtime/ServiceTaskTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/runtime/ServiceTaskTest.java @@ -21,7 +21,10 @@ import org.flowable.cmmn.api.runtime.CaseInstance; import org.flowable.cmmn.api.runtime.PlanItemInstance; import org.flowable.cmmn.api.runtime.PlanItemInstanceState; +import org.flowable.cmmn.engine.impl.behavior.CmmnTriggerableActivityBehavior; import org.flowable.cmmn.engine.impl.delegate.CmmnDelegateHelper; +import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; +import org.flowable.cmmn.engine.impl.util.CommandContextUtil; import org.flowable.cmmn.engine.test.CmmnDeployment; import org.flowable.cmmn.engine.test.FlowableCmmnTestCase; import org.flowable.cmmn.model.CmmnElement; @@ -219,6 +222,42 @@ public void testCreateFieldExpressionForLifecycleListenerWithDelegateHelper() { assertThat(variable).isEqualTo(99L); } + @Test + @CmmnDeployment + public void testStoreTransientVariable() { + CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .start(); + + Object transientResult = cmmnRuntimeService.getVariable(caseInstance.getId(), "transientResult"); + Object persistentResult = cmmnRuntimeService.getVariable(caseInstance.getId(), "persistentResult"); + + assertThat(transientResult).isNull(); + assertThat(persistentResult).isEqualTo("Result is: test"); + } + + @Test + @CmmnDeployment + public void testCmmnTriggerableActivityBehavior() { + CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .start(); + + // The service task here acts like a wait state. + // When the case instance is started, it will wait and be in state ACTIVE. + + PlanItemInstance planItemInstance = cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(caseInstance.getId()).singleResult(); + assertThat(planItemInstance.getState()).isEqualTo(PlanItemInstanceState.ACTIVE); + + // When triggered, the plan item will complete + cmmnRuntimeService.createPlanItemInstanceTransitionBuilder(planItemInstance.getId()).trigger(); + + assertCaseInstanceEnded(caseInstance); + assertThat(cmmnHistoryService.createHistoricPlanItemInstanceQuery().planItemInstanceCaseInstanceId(caseInstance.getId()).singleResult().getState()) + .isEqualTo(PlanItemInstanceState.COMPLETED); + + } + public static class TestJavaDelegate01 implements PlanItemJavaDelegate { public static CmmnModel cmmnModel; @@ -243,6 +282,20 @@ public void execute(DelegatePlanItemInstance planItemInstance) { } + public static class TestJavaDelegate03 implements CmmnTriggerableActivityBehavior { + + @Override + public void execute(DelegatePlanItemInstance delegatePlanItemInstance) { + // Do nothing, wait state + } + + @Override + public void trigger(DelegatePlanItemInstance planItemInstance) { + CommandContextUtil.getAgenda().planCompletePlanItemInstanceOperation((PlanItemInstanceEntity) planItemInstance); + } + + } + public static class TestLifecycleListener01 implements PlanItemInstanceLifecycleListener { @Override @@ -263,18 +316,4 @@ public void stateChanged(DelegatePlanItemInstance planItemInstance, String oldSt } - @Test - @CmmnDeployment - public void testStoreTransientVariable() { - CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("myCase") - .start(); - - Object transientResult = cmmnRuntimeService.getVariable(caseInstance.getId(), "transientResult"); - Object persistentResult = cmmnRuntimeService.getVariable(caseInstance.getId(), "persistentResult"); - - assertThat(transientResult).isNull(); - assertThat(persistentResult).isEqualTo("Result is: test"); - } - } diff --git a/modules/flowable-cmmn-engine/src/test/resources/org/flowable/cmmn/test/runtime/ServiceTaskTest.testCmmnTriggerableActivityBehavior.cmmn b/modules/flowable-cmmn-engine/src/test/resources/org/flowable/cmmn/test/runtime/ServiceTaskTest.testCmmnTriggerableActivityBehavior.cmmn new file mode 100644 index 00000000000..a365772b9c3 --- /dev/null +++ b/modules/flowable-cmmn-engine/src/test/resources/org/flowable/cmmn/test/runtime/ServiceTaskTest.testCmmnTriggerableActivityBehavior.cmmn @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/modules/flowable-cmmn-spring/src/test/java/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.java b/modules/flowable-cmmn-spring/src/test/java/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.java new file mode 100644 index 00000000000..a31971b30b7 --- /dev/null +++ b/modules/flowable-cmmn-spring/src/test/java/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.java @@ -0,0 +1,96 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * 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.flowable.spring.test.el; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.flowable.cmmn.api.CmmnRuntimeService; +import org.flowable.cmmn.api.delegate.DelegatePlanItemInstance; +import org.flowable.cmmn.api.delegate.PlanItemJavaDelegate; +import org.flowable.cmmn.api.runtime.CaseInstance; +import org.flowable.cmmn.api.runtime.PlanItemInstance; +import org.flowable.cmmn.api.runtime.PlanItemInstanceState; +import org.flowable.cmmn.engine.impl.behavior.CmmnTriggerableActivityBehavior; +import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; +import org.flowable.cmmn.engine.impl.util.CommandContextUtil; +import org.flowable.cmmn.engine.test.CmmnDeployment; +import org.flowable.cmmn.engine.test.FlowableCmmnRule; +import org.junit.Rule; +import org.junit.Test; + +/** + * @author Joram Barrez + */ +public class SpringPlanItemJavaDelegateExpressionTest { + + @Rule + public FlowableCmmnRule cmmnRule = new FlowableCmmnRule("org/flowable/spring/test/el/SpringBeanTest-context.xml"); + + @Test + @CmmnDeployment + public void testCmmnTriggerableActivityBehaviorDelegateExpression() { + CmmnRuntimeService cmmnRuntimeService = cmmnRule.getCmmnRuntimeService(); + CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .start(); + + // The service task here acts like a wait state. + // When the case instance is started, it will wait and be in state ACTIVE. + + PlanItemInstance planItemInstance = cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(caseInstance.getId()).singleResult(); + assertThat(planItemInstance.getState()).isEqualTo(PlanItemInstanceState.ACTIVE); + + // When triggered, the plan item will complete + cmmnRuntimeService.createPlanItemInstanceTransitionBuilder(planItemInstance.getId()).trigger(); + + assertThat(cmmnRule.getCmmnHistoryService().createHistoricPlanItemInstanceQuery().planItemInstanceCaseInstanceId(caseInstance.getId()).singleResult().getState()) + .isEqualTo(PlanItemInstanceState.COMPLETED); + } + + @Test + @CmmnDeployment + public void testPlanItemJavaDelegateExpression() { + CmmnRuntimeService cmmnRuntimeService = cmmnRule.getCmmnRuntimeService(); + CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .start(); + + assertThat(cmmnRule.getCmmnHistoryService().createHistoricVariableInstanceQuery() + .caseInstanceId(caseInstance.getId()).singleResult().getValue()).isEqualTo(true); + } + + public static class TestJavaDelegate01 implements CmmnTriggerableActivityBehavior { + + @Override + public void execute(DelegatePlanItemInstance delegatePlanItemInstance) { + // Do nothing, wait state + } + + @Override + public void trigger(DelegatePlanItemInstance planItemInstance) { + CommandContextUtil.getAgenda().planCompletePlanItemInstanceOperation((PlanItemInstanceEntity) planItemInstance); + } + + } + + public static class TestJavaDelegate02 implements PlanItemJavaDelegate { + + @Override + public void execute(DelegatePlanItemInstance delegatePlanItemInstance) { + delegatePlanItemInstance.setVariable("delegateVariable", true); + } + + } + + +} diff --git a/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringBeanTest-context.xml b/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringBeanTest-context.xml index c8b62dbc501..0bfab8d08d8 100644 --- a/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringBeanTest-context.xml +++ b/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringBeanTest-context.xml @@ -32,4 +32,7 @@ + + + \ No newline at end of file diff --git a/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.testCmmnTriggerableActivityBehaviorDelegateExpression.cmmn b/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.testCmmnTriggerableActivityBehaviorDelegateExpression.cmmn new file mode 100644 index 00000000000..61659801995 --- /dev/null +++ b/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.testCmmnTriggerableActivityBehaviorDelegateExpression.cmmn @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.testPlanItemJavaDelegateExpression.cmmn b/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.testPlanItemJavaDelegateExpression.cmmn new file mode 100644 index 00000000000..8ef2c527a62 --- /dev/null +++ b/modules/flowable-cmmn-spring/src/test/resources/org/flowable/spring/test/el/SpringPlanItemJavaDelegateExpressionTest.testPlanItemJavaDelegateExpression.cmmn @@ -0,0 +1,20 @@ + + + + + + + + + + + + + +