02-22-2018 06:18 AM
Note: This is a clone of my original post located in the wrong forum: How to update task property of type NodeRef using REST API?
Hi,
I'm working on a project which integrates with Alfresco v4.2.e and Activiti v5.13.
I use the REST API to query for tasks through the task-instance service.
When a property is a (collection of) NodeRef, It returns a (collection of) string ("workspace://....").
When I try to update this property, Alfresco throws a ClassCastException saying that String cannot be cast to NodeRef.
I found this bug on your jira https://community.alfresco.com/external-link.jspa?url=https%3A%2F%2Fissues.alfresco.com%2Fjira%2Fbro... which seems to be related to my problem but in the other direction. Is my problem a bug? Is this a bug fixed in the v4.2.f? Did I do something wrong?
Anyway I decided to try the activiti-rest webapp to query directly Activiti. So I searched the war for the 5.13.
Unfortunately the Activiti website doesn't provide a long history of binaries. I had to build the war using the sources from github. When I deployed the compiled war to a Tomcat and tried to get variables through the runtime/tasks service, It throws a ActivitiException "unknown variable type name alfrescoScriptNodeList". Indeed in some Maven repo I've seen some Activiti jars suffixed by "alf". Did I built the wrong war? Is there a fork of the project?
Finally I could write a webscript in Alfresco using the Alfresco Java API but it would be the last option...
Sorry for the length of this text and thanks in advance for your answers.
02-28-2018 09:24 AM
No one has an answer? I can't imagine I'm the only one who would like to update a nodeRef inside a task using REST...
03-06-2018 04:53 PM
It isn't really clear what you are trying to do.
That might help people assist you.
03-11-2018 04:57 PM
You're right I missed some crucial information. My apologies
I use the Workflow repository from the Alfresco Community Edition 4.2.e Rest API, documented here: Workflow | Alfresco Documentation
To get a specific workflow instance, I use the endpoint documented here: Get workflow instance | Alfresco Documentation. Some task instances of a workflow instance have a property of type NodeRef.
In the JSON response, a NodeRef property is represented as follow:
"taskPropertyName":
[
"workspace:\/\/SpacesStore\/5f654948-8a55-4b46-8bb6-9b8e5db7cdec"
]
Now I want to update some properties of a task instance. For that I use the endpoint documented here: Updates workflow task instance | Alfresco Documentation.
The task instance is well updated except if I include a property of type NodeRef.
In that case I receive a status code 500 from the Alfresco REST API. When I check the logs of Alfresco, I see this stacktrace:
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to org.alfresco.service.cmr.repository.NodeRef
at org.alfresco.repo.workflow.activiti.ActivitiNodeConverter.convertNodes(ActivitiNodeConverter.java:59)
at org.alfresco.repo.workflow.AbstractWorkflowNodeConverter.convertNodes(AbstractWorkflowNodeConverter.java:71)
at org.alfresco.repo.workflow.AbstractWorkflowNodeConverter.convertNodes(AbstractWorkflowNodeConverter.java:47)
at org.alfresco.repo.workflow.AbstractWorkflowPropertyHandler.convertAssociationValue(AbstractWorkflowPropertyHandler.java:106)
at org.alfresco.repo.workflow.AbstractWorkflowPropertyHandler.handleAssociation(AbstractWorkflowPropertyHandler.java:60)
at org.alfresco.repo.workflow.AbstractWorkflowPropertyHandler.handleDefaultProperty(AbstractWorkflowPropertyHandler.java:166)
at org.alfresco.repo.workflow.DefaultWorkflowPropertyHandler.handleProperty(DefaultWorkflowPropertyHandler.java:38)
at org.alfresco.repo.workflow.WorkflowPropertyHandlerRegistry.handleVariablesToSet(WorkflowPropertyHandlerRegistry.java:75)
at org.alfresco.repo.workflow.activiti.properties.ActivitiPropertyConverter.setTaskProperties(ActivitiPropertyConverter.java:789)
at org.alfresco.repo.workflow.activiti.properties.ActivitiPropertyConverter.updateTask(ActivitiPropertyConverter.java:1050)
at org.alfresco.repo.workflow.activiti.ActivitiWorkflowEngine.updateTask(ActivitiWorkflowEngine.java:2167)
at org.alfresco.repo.workflow.WorkflowServiceImpl.updateTask(WorkflowServiceImpl.java:951)
In the PUT HTTP method, I set the property of type NodeRef as follow:
"taskPropertyName":["workspace://SpacesStore/f7be95e4-3b0b-4519-bdb6-06c2dd9685cf"]
I talked about the Activiti REST API as a workaround: I installed it and configured with the same database as the Activiti bundled with Alfresco to see if I could update task instances by this way. But it's not a good idea.
I hope I have been clearer and thanks for your help.
03-19-2018 09:39 AM
As a workaround I ended up writing a Webscript which do the same as the Alfresco one but with NodeRef handling.
I'ts a bit dirty as I had to parse the string to see if it starts with "workspace://.."
Anyway I'm always interested if someone has the solution or a better workaround.
Here's the code :
public class UpdateTaskProperties extends AbstractWebScript {
private static final String TASK_ID_PARAM = "taskId";
private static Logger LOGGER = LoggerFactory.getLogger(UpdateTaskProperties.class);
private final ObjectMapper objectMapper = new ObjectMapper();
private final NodeRefObjectMapper nodeRefObjectMapper = new NodeRefObjectMapper();
public UpdateTaskProperties() {
}
@Override
public void execute(WebScriptRequest request, WebScriptResponse response) throws IOException {
String taskId = getTaskIdIn(request);
Map<String, Object> properties = objectMapper.readValue(request.getContent().getReader(), Map.class);
Map<String, Object> finalProperties = collectCastedPropertiesFrom(properties);
LOGGER.debug("Updating " + finalProperties.size() + " properties of task " + taskId + "...");
taskService.setVariablesLocal(taskId, finalProperties);
LOGGER.info("Updated " + finalProperties.size() + " properties of task " + taskId);
}
private String getTaskIdIn(WebScriptRequest request) {
String taskId = request.getParameter(TASK_ID_PARAM);
isTrue(isNotBlank(taskId), "Invalid task id");
return taskId;
}
private Map<String, Object> collectCastedPropertiesFrom(Map<String, Object> properties) {
Map<String, Object> finalProperties = newHashMap();
for (String propertyName : properties.keySet()) {
Object value = properties.get(propertyName);
if (nodeRefObjectMapper.isNodeRef(value)) {
finalProperties.put(propertyName, nodeRefObjectMapper.readValue(value));
} else if (nodeRefObjectMapper.isNodeRefCollection(value)) {
finalProperties.put(propertyName, nodeRefObjectMapper.readValues(value));
} else {
finalProperties.put(propertyName, value);
}
}
return finalProperties;
}
}
public class NodeRefObjectMapper {
private static final String WORKSPACE_PREFIX = "workspace://SpacesStore/";
private static final String NOTHING = "";
public NodeRef readValue(Object value) {
isTrue(isNodeRef(value), "Not a NodeRef object");
return toNodeRef((String) value);
}
public Collection<NodeRef> readValues(Object value) {
isTrue(isNodeRefCollection(value), "Not a NodeRef collection object");
return from((Collection<String>) value)
.transform(s -> toNodeRef(s)).toList();
}
public boolean isNodeRef(Object value) {
return value instanceof String && normalize((String) value).startsWith(WORKSPACE_PREFIX);
}
public boolean isNodeRefCollection(Object value) {
return value instanceof Collection
&& !((Collection) value).isEmpty()
&& isNodeRef(((Collection) value).iterator().next());
}
private NodeRef toNodeRef(String value) {
return new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, toNodeRefId(value));
}
private String toNodeRefId(String nodeRef) {
return normalize(nodeRef).replace(WORKSPACE_PREFIX, NOTHING);
}
private String normalize(String value) {
return value.replace("\\", "");
}
}
Explore our Alfresco products with the links below. Use labels to filter content by product module.