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 task I see my new file.
But the value is not saved (lost) after revise / review and in the next task 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 calling the WebScript.
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?
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.