Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BPMSPL-55 - [GSS-RFE] Able to use 'Task Variables' as expressions in …
…Task properties / JBPM-4147 - Able to use 'Task Variables' as expressions in Task properties
- Loading branch information
1 parent
e7a641e
commit aafba25
Showing
10 changed files
with
266 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
jbpm-bpmn2/src/test/resources/BPMN2-UserTaskWithParametrizedInput.bpmn2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,76 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<definitions id="Definition" | |||
targetNamespace="http://www.example.org/MinimalExample" | |||
typeLanguage="http://www.java.com/javaTypes" | |||
expressionLanguage="http://www.mvel.org/2.0" | |||
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" | |||
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" | |||
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" | |||
xmlns:di="http://www.omg.org/spec/DD/20100524/DI" | |||
xmlns:tns="http://www.jboss.org/drools"> | |||
|
|||
<itemDefinition id="_sItem" structureRef="String" /> | |||
<process processType="Private" isExecutable="true" id="UserTask" name="User Task" > | |||
<property id="s" itemSubjectRef="_sItem"/> | |||
<!-- nodes --> | |||
<startEvent id="_1" name="StartProcess" /> | |||
<userTask id="_2" name="Hello" > | |||
|
|||
<ioSpecification> | |||
<dataInput id="_067D221E-E8BD-4AD5-9A90-FB204A0E89F9_UrlInputX" name="Description"/> | |||
<inputSet> | |||
<dataInputRefs>_067D221E-E8BD-4AD5-9A90-FB204A0E89F9_UrlInputX</dataInputRefs> | |||
</inputSet> | |||
<outputSet> | |||
</outputSet> | |||
</ioSpecification> | |||
<dataInputAssociation id="_mZWjtlOZEeSBDLLXGrwEZw"> | |||
<targetRef>_067D221E-E8BD-4AD5-9A90-FB204A0E89F9_UrlInputX</targetRef> | |||
<assignment id="_mZWjt1OZEeSBDLLXGrwEZw"> | |||
<from xsi:type="tFormalExpression" id="_mZWjuFOZEeSBDLLXGrwEZw"> | |||
<![CDATA[Executing task of process instance #{processInstance.id} as work item with #{nodeInstance.nodeName}]]> | |||
</from> | |||
<to xsi:type="tFormalExpression" id="_mZWjuVOZEeSBDLLXGrwEZw">_067D221E-E8BD-4AD5-9A90-FB204A0E89F9_UrlInputX</to> | |||
</assignment> | |||
</dataInputAssociation> | |||
<potentialOwner> | |||
<resourceAssignmentExpression> | |||
<formalExpression>john</formalExpression> | |||
</resourceAssignmentExpression> | |||
</potentialOwner> | |||
</userTask> | |||
<endEvent id="_3" name="EndProcess" > | |||
<terminateEventDefinition/> | |||
</endEvent> | |||
|
|||
<!-- connections --> | |||
<sequenceFlow id="_1-_2" sourceRef="_1" targetRef="_2" /> | |||
<sequenceFlow id="_2-_3" sourceRef="_2" targetRef="_3" /> | |||
|
|||
</process> | |||
|
|||
<bpmndi:BPMNDiagram> | |||
<bpmndi:BPMNPlane bpmnElement="UserTask" > | |||
<bpmndi:BPMNShape bpmnElement="_1" > | |||
<dc:Bounds x="16" y="16" width="48" height="48" /> | |||
</bpmndi:BPMNShape> | |||
<bpmndi:BPMNShape bpmnElement="_2" > | |||
<dc:Bounds x="96" y="16" width="100" height="48" /> | |||
</bpmndi:BPMNShape> | |||
<bpmndi:BPMNShape bpmnElement="_3" > | |||
<dc:Bounds x="228" y="16" width="48" height="48" /> | |||
</bpmndi:BPMNShape> | |||
<bpmndi:BPMNEdge bpmnElement="_1-_2" > | |||
<di:waypoint x="40" y="40" /> | |||
<di:waypoint x="146" y="40" /> | |||
</bpmndi:BPMNEdge> | |||
<bpmndi:BPMNEdge bpmnElement="_2-_3" > | |||
<di:waypoint x="146" y="40" /> | |||
<di:waypoint x="252" y="40" /> | |||
</bpmndi:BPMNEdge> | |||
</bpmndi:BPMNPlane> | |||
</bpmndi:BPMNDiagram> | |||
|
|||
</definitions> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
|
@@ -6,15 +6,23 @@ | ||
|
|
||
import java.util.ArrayList; | import java.util.ArrayList; | ||
import java.util.Date; | import java.util.Date; | ||
import java.util.HashMap; | |||
import java.util.List; | import java.util.List; | ||
import java.util.Map; | import java.util.Map; | ||
import java.util.regex.Matcher; | |||
import java.util.regex.Pattern; | |||
|
|
||
import org.drools.core.process.instance.WorkItem; | |||
import org.drools.core.util.MVELSafeHelper; | |||
import org.jbpm.process.core.context.variable.VariableScope; | |||
import org.jbpm.process.instance.context.variable.VariableScopeInstance; | |||
import org.jbpm.services.task.commands.TaskCommand; | import org.jbpm.services.task.commands.TaskCommand; | ||
import org.jbpm.services.task.commands.TaskContext; | import org.jbpm.services.task.commands.TaskContext; | ||
import org.jbpm.services.task.events.TaskEventSupport; | import org.jbpm.services.task.events.TaskEventSupport; | ||
import org.jbpm.services.task.internals.lifecycle.LifeCycleManager; | import org.jbpm.services.task.internals.lifecycle.LifeCycleManager; | ||
import org.jbpm.services.task.utils.ClassUtil; | import org.jbpm.services.task.utils.ClassUtil; | ||
import org.jbpm.services.task.utils.ContentMarshallerHelper; | import org.jbpm.services.task.utils.ContentMarshallerHelper; | ||
import org.jbpm.workflow.instance.impl.NodeInstanceResolverFactory; | |||
import org.kie.api.command.Command; | import org.kie.api.command.Command; | ||
import org.kie.api.runtime.Environment; | import org.kie.api.runtime.Environment; | ||
import org.kie.api.task.model.Content; | import org.kie.api.task.model.Content; | ||
|
@@ -45,6 +53,8 @@ public class TaskInstanceServiceImpl implements TaskInstanceService { | ||
|
|
||
private static final Logger logger = LoggerFactory.getLogger(TaskInstanceServiceImpl.class); | private static final Logger logger = LoggerFactory.getLogger(TaskInstanceServiceImpl.class); | ||
|
|
||
protected static final Pattern PARAMETER_MATCHER = Pattern.compile("\\$\\{([\\S&&[^\\}]]+)\\}", Pattern.DOTALL); | |||
|
|||
private LifeCycleManager lifeCycleManager; | private LifeCycleManager lifeCycleManager; | ||
|
|
||
private org.kie.internal.task.api.TaskContext context; | private org.kie.internal.task.api.TaskContext context; | ||
|
@@ -83,30 +93,39 @@ public void setPersistenceContext(TaskPersistenceContext persistenceContext) { | ||
public long addTask(Task task, Map<String, Object> params) { | public long addTask(Task task, Map<String, Object> params) { | ||
taskEventSupport.fireBeforeTaskAdded(task, context); | taskEventSupport.fireBeforeTaskAdded(task, context); | ||
|
|
||
persistenceContext.persistTask(task); | |||
|
|||
resolveTaskDetailsForTaskProperties(task); | |||
resolveTaskDetails(params, task); | |||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
mswiderski
Author
Contributor
|
|||
|
|||
if (params != null) { | if (params != null) { | ||
ContentData contentData = ContentMarshallerHelper.marshal(params, environment); | ContentData contentData = ContentMarshallerHelper.marshal(params, TaskContentRegistry.get().getMarshallerContext(task).getEnvironment()); | ||
Content content = TaskModelProvider.getFactory().newContent(); | Content content = TaskModelProvider.getFactory().newContent(); | ||
((InternalContent) content).setContent(contentData.getContent()); | ((InternalContent) content).setContent(contentData.getContent()); | ||
persistenceContext.persistContent(content); | persistenceContext.persistContent(content); | ||
((InternalTaskData) task.getTaskData()).setDocument( | ((InternalTaskData) task.getTaskData()).setDocument(content.getId(), contentData); | ||
content.getId(), contentData); | |||
} | } | ||
|
|
||
persistenceContext.persistTask(task); |
|
||
taskEventSupport.fireAfterTaskAdded(task, context); | taskEventSupport.fireAfterTaskAdded(task, context); | ||
return task.getId(); | return task.getId(); | ||
} | } | ||
|
|
||
public long addTask(Task task, ContentData contentData) { | public long addTask(Task task, ContentData contentData) { | ||
taskEventSupport.fireBeforeTaskAdded(task, context); | taskEventSupport.fireBeforeTaskAdded(task, context); | ||
if (contentData != null) { |
|
||
persistenceContext.persistTask(task); | |||
|
|||
resolveTaskDetailsForTaskProperties(task); | |||
|
|||
if (contentData != null) { | |||
Content content = TaskModelProvider.getFactory().newContent(); | Content content = TaskModelProvider.getFactory().newContent(); | ||
((InternalContent) content).setContent(contentData.getContent()); | ((InternalContent) content).setContent(contentData.getContent()); | ||
persistenceContext.persistContent(content); | persistenceContext.persistContent(content); | ||
((InternalTaskData) task.getTaskData()).setDocument(content.getId(), contentData); | ((InternalTaskData) task.getTaskData()).setDocument(content.getId(), contentData); | ||
} | } | ||
|
|
||
persistenceContext.persistTask(task); |
|
||
taskEventSupport.fireAfterTaskAdded(task, context); | taskEventSupport.fireAfterTaskAdded(task, context); | ||
return task.getId(); | return task.getId(); | ||
} | } | ||
|
@@ -357,4 +376,48 @@ protected List<String> toGroups(List<String> groups) { | ||
|
|
||
return groups; | return groups; | ||
} | } | ||
|
|||
protected Map<String, Object> resolveTaskDetails(Map<String, Object> parameters, Task task) { | |||
for (Map.Entry<String, Object> entry: parameters.entrySet()) { | |||
if (entry.getValue() != null && entry.getValue() instanceof String) { | |||
String s = (String) entry.getValue(); | |||
Map<String, String> replacements = new HashMap<String, String>(); | |||
Matcher matcher = PARAMETER_MATCHER.matcher(s); | |||
while (matcher.find()) { | |||
String paramName = matcher.group(1); | |||
if (replacements.get(paramName) == null) { | |||
|
|||
try { | |||
Object variableValue = MVELSafeHelper.getEvaluator().eval(paramName, new TaskResolverFactory(task)); | |||
String variableValueString = variableValue == null ? "" : variableValue.toString(); | |||
replacements.put(paramName, variableValueString); | |||
} catch (Throwable t) { | |||
|
|||
logger.error("Continuing without setting parameter."); | |||
} | |||
} | |||
|
|||
} | |||
for (Map.Entry<String, String> replacement: replacements.entrySet()) { | |||
s = s.replace("${" + replacement.getKey() + "}", replacement.getValue()); | |||
} | |||
parameters.put(entry.getKey(), s); | |||
} | |||
} | |||
return parameters; | |||
} | |||
|
|||
protected void resolveTaskDetailsForTaskProperties(Task task) { | |||
Map<String, Object> parameters = new HashMap<String, Object>(); | |||
parameters.put("name", task.getName()); | |||
parameters.put("description", task.getDescription()); | |||
parameters.put("subject", task.getSubject()); | |||
parameters.put("formName", ((InternalTask)task).getFormName()); | |||
|
|||
Map<String, Object> replacements = resolveTaskDetails(parameters, task); | |||
((InternalTask)task).setName((String) replacements.get("name")); | |||
((InternalTask)task).setDescription((String) replacements.get("description")); | |||
((InternalTask)task).setSubject((String) replacements.get("subject")); | |||
((InternalTask)task).setFormName((String) replacements.get("formName")); | |||
} | |||
} | } |
27 changes: 27 additions & 0 deletions
27
...k/jbpm-human-task-core/src/main/java/org/jbpm/services/task/impl/TaskResolverFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,27 @@ | |||
package org.jbpm.services.task.impl; | |||
|
|||
import org.kie.api.task.model.Task; | |||
import org.mvel2.integration.VariableResolver; | |||
import org.mvel2.integration.impl.ImmutableDefaultFactory; | |||
import org.mvel2.integration.impl.SimpleValueResolver; | |||
|
|||
|
|||
public class TaskResolverFactory extends ImmutableDefaultFactory { | |||
|
|||
private static final long serialVersionUID = 8019024969834990593L; | |||
private Task task; | |||
|
|||
public TaskResolverFactory(Task task) { | |||
this.task = task; | |||
} | |||
public boolean isResolveable(String name) { | |||
return "task".equals(name); | |||
} | |||
|
|||
|
|||
public VariableResolver getVariableResolver(String name) { | |||
|
|||
return new SimpleValueResolver(task); | |||
} | |||
|
|||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
@mswiderski This looks wrong to me. We are using the params before checking if they are null. If Params is null, the resolveTaskDetails() method will blow up! :)