Skip to content

Commit

Permalink
Cmmn: fix plan item java delegate trigger not possible
Browse files Browse the repository at this point in the history
  • Loading branch information
jbarrez committed Jun 1, 2020
1 parent 2fbfd84 commit 65bd7ab
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 18 deletions.
Expand Up @@ -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;
Expand All @@ -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<FieldExtension> fieldExtensions;
Expand All @@ -52,18 +53,39 @@ 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) {
throw new FlowableException(exc.getMessage(), exc);
}
}

@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);
}
}

}
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -53,13 +54,30 @@ 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);

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;

Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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");
}

}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL"
xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC"
xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI"
xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:flowable="http://flowable.org/cmmn"
targetNamespace="http://flowable.org/cmmn">

<case id="myCase">
<casePlanModel id="myPlanModel" name="My CasePlanModel">

<planItem id="planItem1" name="Task One" definitionRef="serviceTask" />

<task id="serviceTask" flowable:type="java" flowable:class="org.flowable.cmmn.test.runtime.ServiceTaskTest$TestJavaDelegate03" />

</casePlanModel>
</case>

</definitions>
@@ -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);
}

}


}
Expand Up @@ -32,4 +32,7 @@

<bean id="customBean" class="org.flowable.spring.test.el.CustomBean" />

<bean id="testTriggerableDelegate01" class="org.flowable.spring.test.el.SpringPlanItemJavaDelegateExpressionTest$TestJavaDelegate01"/>
<bean id="testTriggerableDelegate02" class="org.flowable.spring.test.el.SpringPlanItemJavaDelegateExpressionTest$TestJavaDelegate02"/>

</beans>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL"
xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC"
xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI"
xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:flowable="http://flowable.org/cmmn"
targetNamespace="http://flowable.org/cmmn">

<case id="myCase">
<casePlanModel id="myPlanModel" name="My CasePlanModel">

<planItem id="planItem1" name="Task One" definitionRef="serviceTask" />

<task id="serviceTask" flowable:type="java" flowable:delegateExpression="${testTriggerableDelegate01}" />

</casePlanModel>
</case>

</definitions>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL"
xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC"
xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI"
xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:flowable="http://flowable.org/cmmn"
targetNamespace="http://flowable.org/cmmn">

<case id="myCase">
<casePlanModel id="myPlanModel" name="My CasePlanModel">

<planItem id="planItem1" name="Task One" definitionRef="serviceTask" />

<task id="serviceTask" flowable:type="java" flowable:delegateExpression="${testTriggerableDelegate02}" />

</casePlanModel>
</case>

</definitions>

0 comments on commit 65bd7ab

Please sign in to comment.