How to add additional attachments in the workflow?

cancel
Showing results for 
Search instead for 
Did you mean: 
alekseybykov
Established Member II

How to add additional attachments in the workflow?

Jump to solution

My environment:

 Alfresco Share v5.2.d (r134641-b15, Aikau 1.0.101.3, Spring Surf 5.2.d, Spring WebScripts 6.13, Freemarker 2.3.20-alfresco-patched, Rhino 1.7R4-alfresco-patched, Yui 2.9.0-alfresco-20141223)

 Alfresco Community v5.2.0 (r134428-b13) schema 10005

In my document management process it is often necessary to provide some additional documents (e.g. list of comments, list of differences, some screenshot, etc).

These additional documents would be convenient to add in the Activiti forms. I would like to be able to add documents at the initiation stage of a business process and at the stage of the revise.

For this, I added an aspect with associations in the workflow-model.xml (relevant part):

...
<type name="mswf:activitiRevise">
    ...
    <mandatory-aspects>
        ...
        <aspect>mswf:attachments</aspect>
    </mandatory-aspects>
</type>       
...
<aspect name="mswf:attachments">
    <associations>
        <association name="mswf:package">
            <source>
                <mandatory>false</mandatory>
                <many>true</many>
            </source>
            <target>
                <class>cm:content</class>
                <mandatory>false</mandatory>
                <many>true</many>
            </target>
        </association>
    </associations>     
</aspect>  
...
etc

In share-config-custom.xml I have the following (relevant part):

...
<config evaluator="task-type" condition="bpm:startTask">
    <forms>
        <form id="workflow-details">
            <field-visibility>
                ...
                <show id="mswf:package" />
            </field-visibility>
            <appearance>
                ...
                <set id="attachments" appearance="title" label-id="Additional docs" />
                <field id="mswf:package" set="attachments" />
            </appearance>
        </form>
        <form>
            <field-visibility>
                <show id="mswf:package" />
                ...
            </field-visibility>
            <appearance>
                <set id="attachments" appearance="title" label-id="Additional docs" />
                <field id="mswf:package" set="attachments" />
                ...
            </appearance>
        </form>
    </forms>
</config>
...
etc‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Now I have an additional field where I can choose the appropriate documents.

It works - I added some documents and can see them at all of the stages of the document management process.

The problem occurs when I try to change a set of initially selected files. For example, when I try to add a new one. If I add a new one (or remove) - changes are not saved and in the next task, I see the same documents that were selected at the beginning.

To get control of this behavior, I developed WebScript, in which I try to manage properties. I call the WebScript from Share in the getAddedItems() method:

/**
* Returns items that have been added to the current value
*
* @method getAddedItems
* @return {array}
*/

getAddedItems: function ObjectFinder_getAddedItems() {
    var addedItems = [],
    currentItems = Alfresco.util.arrayToObject(this.options.currentValue.split(","));

    for (var item in this.selectedItems) {
        if (this.selectedItems.hasOwnProperty(item)) {
            if (!(item in currentItems)) {
                addedItems.push(item);                    
            }
        }
    }

    ...

    // here the call to the WebScript

    return addedItems;
},

Part of my Java-backed WebScript:

...
public class WorkflowAttachmentsManipulator extends DeclarativeWebScript  {
    private static final String WORKFLOW_MODEL_URI = "...";
    private WorkflowService workflowService;

    @Override
    protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {
        Map<String, Object> model = new HashMap<>();

        String taskId = req.getParameter("taskId");
        String addedItem = req.getParameter("addedItem");

        WorkflowTask workflowTask = workflowService.getTaskById(taskId);
        Map<QName, Serializable> taskProperties = workflowTask.getProperties();

        ...
        taskProperties.replace(
            QName.createQName(WORKFLOW_MODEL_URI, "package"), oldValue, addedItem);
        workflowService.updateTask(taskId, taskProperties, null, null);

...‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I'm trying to replace the selected files with some arbitrary and the replace(...) method returns true. In alfrescotomcat-stdout.2017-09-06.log I also see that the property has been replaced:

Before calling the WebScript (two files in the package):

key: {WORKFLOW_MODEL_URI_HERE}package
value: [workspace://SpacesStore/7f980005-2a1b-49a5-a8ff-ce9dff31a98a,
        workspace://SpacesStore/30d9122f-4467-451b-aeab-ca8b164f7769]‍‍‍‍‍‍‍‍‍‍‍‍

After calling the WebScript (one file in the package):

key: {WORKFLOW_MODEL_URI_HERE}package
value: workspace://SpacesStore/1a0b110f-1e09-4ca2-b367-fe25e4964a4e‍‍‍‍‍‍‍‍

After updating the form at the current stage I see my new file.

But the value is not saved (lost) after revise / review and at the next stage I see the same files. Let's say, the task ID for the current user was activiti$204587, then it became equals activiti$204647...

I added some debugging code to the BPMN diagram and found that the contents of mswf_package did not change after the web script was called.

In 'Submit', main config:

for(var i = 0; i < mswf_package.size(); i++) {     
   logger.log(mswf_package.get(i).nodeRef);
}‍‍‍

Output:

DEBUG [repo.jscript.ScriptLogger] [http-apr-8080-exec-9] workspace://SpacesStore/7f980005-2a1b-49a5-a8ff-ce9dff31a98a
DEBUG [repo.jscript.ScriptLogger] [http-apr-8080-exec-9] workspace://SpacesStore/30d9122f-4467-451b-aeab-ca8b164f7769‍‍

In 'Review Task', listeners of the create and complete events:

for(var i = 0; i < mswf_package.size(); i++) {     
   logger.log(mswf_package.get(i).nodeRef);
}‍‍‍

Output:

DEBUG [repo.jscript.ScriptLogger] [http-apr-8080-exec-9] workspace://SpacesStore/7f980005-2a1b-49a5-a8ff-ce9dff31a98a
DEBUG [repo.jscript.ScriptLogger] [http-apr-8080-exec-9] workspace://SpacesStore/30d9122f-4467-451b-aeab-ca8b164f7769
‍‍

How to add additional attachments in the workflow?... Is it possible?...

I would be very grateful for the information. Thanks to all.

1 Solution

Accepted Solutions
alekseybykov
Established Member II

Re: Is there a way to save changed property of the workflow instance object back to the running workflow instance(attached files as an example)?

Jump to solution

A set of strings with NodeRefs can be passed to the following WebScript, for example:

public class WorkflowAttachmentsManipulator extends DeclarativeWebScript  {
    private static final String WORKFLOW_MODEL_URI = "...";
    private WorkflowService workflowService;

    @Override
    protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {
        Map<String, Object> model = new HashMap<>();

        String taskId = req.getParameter("taskId");
        String addedItems = req.getParameter("addedItems");

        String oldValue = "";

        WorkflowTask workflowTask = workflowService.getTaskById(taskId);
        Map<QName, Serializable> taskProperties = workflowTask.getProperties();

        Iterator taskIterator = taskProperties.entrySet().iterator();
        while(taskIterator.hasNext()) {
            Map.Entry taskPair = (Map.Entry)taskIterator.next();
            Object key = taskPair.getKey();
            if(key != null &&
                key.toString().equalsIgnoreCase("{" + WORKFLOW_MODEL_URI + "}package")) {

                if(taskPair.getValue() != null) {
                    oldValue = taskPair.getValue().toString();
                    if(!oldValue.equals("[]")) {
                        oldValue = oldValue.replaceAll("[\\[\\]]", "");
                        addedItems = "[" + oldValue + "," + addedItems + "]";
                    } else {

                        if(addedItems.indexOf(",") > 0) {
                            addedItems = "[" + addedItems + "]";   
                        }
                    }
                }

                taskProperties.replace(
                    QName.createQName(WORKFLOW_MODEL_URI, "package"),
                    oldValue,
                    addedItems);

                workflowService.updateTask(workflowTask.getId(),
                    taskProperties, null, null);

                break;
            }
        }
        ...
    }

    public WorkflowService getWorkflowService() {
        return workflowService;
    }

    public void setWorkflowService(WorkflowService workflowService) {
        this.workflowService = workflowService;
    }
}

This code overrides attachments for the certain task.

Additional files need to differentiate from those that are involved in the document management process. It can be done, for example, as follows:

/**
* Returns items that have been added to the current value
*
* @method getAddedItems
* @return {array}
*/

getAddedItems: function ObjectFinder_getAddedItems() {
    var addedItems = [],
    currentItems = Alfresco.util.arrayToObject(this.options.currentValue.split(","));

    var attachments = [];

    for (var item in this.selectedItems) {
        if (this.selectedItems.hasOwnProperty(item)) {         
            if (!(item in currentItems)) {
                // modified for differentiation
                if (this.options.displayMode == "items") {
                    attachments.push(item);
                } else {
                    addedItems.push(item);                    
                }
            }
        }
    }

    ...

    // call to the WebScript with attachments

    // modified for merge
    return addedItems.concat(attachments);
},

For saving the overridden attachments in the process variable it is necessary to define the listener of the complete event.

Moreover, it is possible to "pass" files by the chain from task to task (with changes) by using this technique:

Listener of the complete event:

public class TaskCompleteListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        DelegateExecution execution = delegateTask.getExecution();     
        execution.setVariable("mswf_package", delegateTask.getVariable("mswf_package"));
    }
}

Listener of the create event:

public class TaskCreateListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        DelegateExecution execution = delegateTask.getExecution();
        delegateTask.setVariable("mswf_package", execution.getVariable("mswf_package"));
    }
}

This solved my issue.

1 Reply
alekseybykov
Established Member II

Re: Is there a way to save changed property of the workflow instance object back to the running workflow instance(attached files as an example)?

Jump to solution

A set of strings with NodeRefs can be passed to the following WebScript, for example:

public class WorkflowAttachmentsManipulator extends DeclarativeWebScript  {
    private static final String WORKFLOW_MODEL_URI = "...";
    private WorkflowService workflowService;

    @Override
    protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {
        Map<String, Object> model = new HashMap<>();

        String taskId = req.getParameter("taskId");
        String addedItems = req.getParameter("addedItems");

        String oldValue = "";

        WorkflowTask workflowTask = workflowService.getTaskById(taskId);
        Map<QName, Serializable> taskProperties = workflowTask.getProperties();

        Iterator taskIterator = taskProperties.entrySet().iterator();
        while(taskIterator.hasNext()) {
            Map.Entry taskPair = (Map.Entry)taskIterator.next();
            Object key = taskPair.getKey();
            if(key != null &&
                key.toString().equalsIgnoreCase("{" + WORKFLOW_MODEL_URI + "}package")) {

                if(taskPair.getValue() != null) {
                    oldValue = taskPair.getValue().toString();
                    if(!oldValue.equals("[]")) {
                        oldValue = oldValue.replaceAll("[\\[\\]]", "");
                        addedItems = "[" + oldValue + "," + addedItems + "]";
                    } else {

                        if(addedItems.indexOf(",") > 0) {
                            addedItems = "[" + addedItems + "]";   
                        }
                    }
                }

                taskProperties.replace(
                    QName.createQName(WORKFLOW_MODEL_URI, "package"),
                    oldValue,
                    addedItems);

                workflowService.updateTask(workflowTask.getId(),
                    taskProperties, null, null);

                break;
            }
        }
        ...
    }

    public WorkflowService getWorkflowService() {
        return workflowService;
    }

    public void setWorkflowService(WorkflowService workflowService) {
        this.workflowService = workflowService;
    }
}

This code overrides attachments for the certain task.

Additional files need to differentiate from those that are involved in the document management process. It can be done, for example, as follows:

/**
* Returns items that have been added to the current value
*
* @method getAddedItems
* @return {array}
*/

getAddedItems: function ObjectFinder_getAddedItems() {
    var addedItems = [],
    currentItems = Alfresco.util.arrayToObject(this.options.currentValue.split(","));

    var attachments = [];

    for (var item in this.selectedItems) {
        if (this.selectedItems.hasOwnProperty(item)) {         
            if (!(item in currentItems)) {
                // modified for differentiation
                if (this.options.displayMode == "items") {
                    attachments.push(item);
                } else {
                    addedItems.push(item);                    
                }
            }
        }
    }

    ...

    // call to the WebScript with attachments

    // modified for merge
    return addedItems.concat(attachments);
},

For saving the overridden attachments in the process variable it is necessary to define the listener of the complete event.

Moreover, it is possible to "pass" files by the chain from task to task (with changes) by using this technique:

Listener of the complete event:

public class TaskCompleteListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        DelegateExecution execution = delegateTask.getExecution();     
        execution.setVariable("mswf_package", delegateTask.getVariable("mswf_package"));
    }
}

Listener of the create event:

public class TaskCreateListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        DelegateExecution execution = delegateTask.getExecution();
        delegateTask.setVariable("mswf_package", execution.getVariable("mswf_package"));
    }
}

This solved my issue.