Getting **defined** process user tasks and task attributes

I was wondering if it is possible to retrieve the user tasks defined in a deployed process (not and instantiated one).
Currently, the only solution I can think of is to:

  • Add a category to user tasks
  • Retrieve the process definition model (extremely huge object)
  • Filter objects in the mainProcess.flowElements array for objects that have a category matching the required category.

It’s all to aid in dynamically creating a menu of possible user tasks defined for a process.

The other question is that I notice that the flow elements has an attributes property but is always empty in my instances. I’ve looked in the modeler and I’ve searched in the documents but don’t know the why of this property or how it can be populated.

The approach you describe sounds like the way to go: you need to mark the user tasks somehow, if you can’t show them all on the screen. Note that the BpmnModel is always cached in-memory and that the filtering also will happen in-memory. Even if it’s a big process definition, this is very fast.

Not sure which one you’re referring to. Do you have an example?

{
....,
 "flowElements": [
            {
                "id": "centralStartEvent",
                "xmlRowNumber": 5,
                "xmlColumnNumber": 5,
                "extensionElements": {},
                "attributes": {}, <--------------- This one
                "name": null,
                "documentation": null,
                "executionListeners": [],
                "asynchronous": false,
                "notExclusive": false,
                "incomingFlows": [],
                "outgoingFlows": [
                    { ... }
                ],
                "eventDefinitions": [],
                "initiator": "initiator",
                "formKey": null,
                "validateFormFields": null,
                "formProperties": [],
                "interrupting": true,
                "exclusive": true
            },
....
}

Looking at the code, they seem to be extension attributes. Meaning, if you have custom attributes (different xml namespace) in your xml, they’ll end up there. But there’s no possibility to set these in the Modeler, only programmatically or in XML.

Do you have a simple way to pass a custom attribute from XML ? I mean write something like
<humanTask id="HumanTask_0d65dvu" name="define schedule" avalia:apiKey="DefineScheduleApiKey"/>
in the cmmn so it is retrievable from

 "attributes": {}, <--------------- This one

Not on that level, but only on the extensionElements which is possible on each element.
Once there, it can be retrieved in any custom behavior class.

Do you have a simple way to pass a custom attribute from XML ? I mean write something like
<humanTask id="HumanTask_0d65dvu" name="define schedule" avalia:apiKey="DefineScheduleApiKey"/>
in the cmmn so it is retrievable from

I know that for workflow BPMN.xml consumed by the process engine, you have something like this for example:

<userTask id="a3" name="Some Taske" flowable:formFieldValidation="true"  flowable:formKey="a3"
                  flowable:candidateGroups="GROUP_someGroup"
                  flowable:listColumns='[{"type":"text","key":"applicationId","sortable":true}"}]'>

with flowable:listColumns being a custome attribute; but be aware that if you were to import the BPMN.xml into the modeler, the Flowable modeler will literally strip away any custom unrecognised attributes.

Thank you for your answers ! I managed to access my custom attribute as an extensionElement thought it’s a bit a pain to extract afterward :
My CMMN :

        <humanTask id="HumanTask_06epgwk" name="write proposal">
          <extensionElements>
            <avalia:taskType>APITask</avalia:taskType>
            <avalia:apiKey>WriteProposalKey</avalia:formKey>
          </extensionElements>
        </humanTask>

My TaskCreationInterceptor uses reflexion to extract the task type’s class and instantiate it in the correct way (AbstractTask is a “mirror” of a Flowable Task stored on our side, containing logic and data to establish a bridge with the existing system)

    public void notify(CreateHumanTaskAfterContext delegateTask) {

        AbstractTask abstractTask;
        // extracting the task type
        if(delegateTask.getHumanTask().getExtensionElements().containsKey("taskType") &&
            delegateTask.getHumanTask().getExtensionElements().get("taskType").size() == 1) {
            String taskType  = delegateTask
                    .getHumanTask()
                    .getExtensionElements()
                    .get("taskType")
                    .get(0)
                    .getElementText();

            try {
                abstractTask = (AbstractTask) Class.forName(classPath + taskType).getConstructor().newInstance();
            } catch(ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
                // handle class not found
                abstractTask = new DefaultTask();
            }
        }
}