AnsweredAssumed Answered

Bug in workflowService.getTaskDefinitions?

Question asked by arnoldschrijver on May 19, 2012
Latest reply on May 22, 2012 by arnoldschrijver
I am using CE 4.0.b and noticed what looks like a bug in using the workflowService to retrieve the WorkflowTaskDefinition of a task defined as multi-instance in the BPMN workflow definition.

The problem occurs when using the workflow service and calling workflowService.getTaskDefinitions(workflowDefinitionId) on the workflow. Returned results for the multi-instance tasks are incorrect.

During the construction of the returned list, when encountering the multi-instance task it first goes wrong in ActivitiWorkflowEngine.getFormKey() because the task does not derive from UserTaskActivityBehavior (it instead derives from ).
The formkey is set to the localname of the type (variable startId) and there is another chance for a namespace prefix to be looked up in WorkflowObjectFactory.getTaskTypeDefinition(). However, the qNameConverter doesn’t resolve the namespace.
You'll get a 'type not found' warning in the logs (from DictionaryDAOImpl.getType). The WorkflowObjectFactory will now fall back to the defaultStartType (activitiStartTask) instead.

I created a sample project that demonstrates the issue (can't include it to this post). Here are some code fragments:

The activity bpmn should have a multi-instance task e.g. like in the standard Parallel Review and Approve workflow:


        <userTask id="reviewTask" name="Review Task"
            activiti:formKey="wf:activitiReviewTask">
           <extensionElements>
               <activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
                  <activiti:field name="script">
                     <activiti:string>
                        if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate
                        if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;
                     </activiti:string>
                  </activiti:field>
               </activiti:taskListener>
               <activiti:taskListener event="complete" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
                  <activiti:field name="script">
                     <activiti:string>
                        if(task.getVariableLocal('wf_reviewOutcome') == 'Approve') {
                             var newApprovedCount = wf_approveCount + 1;
                             var newApprovedPercentage = (newApprovedCount / wf_reviewerCount) * 100;
                            
                             execution.setVariable('wf_approveCount', newApprovedCount);
                             execution.setVariable('wf_actualPercent', newApprovedPercentage);
                        }
                     </activiti:string>
                  </activiti:field>
               </activiti:taskListener>
           </extensionElements>
          
           <humanPerformer>
                <resourceAssignmentExpression>
                    <formalExpression>${reviewAssignee.properties.userName}</formalExpression>
                </resourceAssignmentExpression>
           </humanPerformer>
          
           <!– For each assignee, task is created –>
           <multiInstanceLoopCharacteristics isSequential="false">
              <loopDataInputRef>bpm_assignees</loopDataInputRef>
              <inputDataItem name="reviewAssignee" />
              <completionCondition>${wf_actualPercent >= wf_requiredApprovePercent}</completionCondition>
           </multiInstanceLoopCharacteristics>
        </userTask>

And then create a java-backed webscript to get to the task definitions:


   @Override
   protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {
      
      Map<String, Object> model = new HashMap<String, Object>();
      
      // Original version of parallel review task
      String workflowDefinitionId = "activiti$activitiParallelReview:1:16";
      
      // Copy of parallel review task but now in SomeCo namespace.
      //String workflowDefinitionId = "activiti$activitiParallelReview:2:4310";
      
      // Look up the id in the workflow console.
      WorkflowDefinition definition = workflowService.getDefinitionById(workflowDefinitionId);   
      
      if (definition != null) {
          List<WorkflowTaskDefinition> tasks = workflowService.getTaskDefinitions(definition.getId());
          List<String> taskIds = new LinkedList<String>();
          for (WorkflowTaskDefinition task : tasks) {
              taskIds.add(task.getId());
          }
         
          model.put("taskIds", taskIds);
      }

      return model;
   }

A simple ftl like this:


<#escape x as jsonUtils.encodeJSONString(x)>
{
    "tasks":
    [
       <#list taskIds as taskId>      
            "${taskId}"<#if taskId_has_next>,</#if>
       </#list>
    ]
}
</#escape>

results in this output:


{
    "tasks":
    [      
            "wf:submitParallelReviewTask",      
            "reviewTask",      
            "wf:approvedParallelTask", 
            "wf:rejectedParallelTask"      
    ]
}

If this is indeed a bug I will create an issue in the Jira…

Outcomes