Merged 5.0.N (5.0.3) to HEAD (5.1)

109441: Merged V4.2-BUG-FIX (4.2.6) to 5.0.N (5.0.3)
      109381: Merged DEV to V4.2-BUG-FIX (4.2.5)
         MNT-11472: [PUBLIC-WORKFLOW-API] Processing of Association Properties in Tasks convert incorrect
            - Dictionary service will be used to find association definition, when assoc def is absent for RestVariableHelper. Also, unit test was added.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@109501 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2015-08-04 09:58:21 +00:00
parent 7ec60dc9c2
commit 8cde3e29eb
6 changed files with 324 additions and 5 deletions

View File

@@ -778,6 +778,7 @@
<bean id="restVariableHelper" class="org.alfresco.rest.workflow.api.impl.RestVariableHelper">
<property name="nodeService" ref="nodeService" />
<property name="namespaceService" ref="namespaceService" />
<property name="dictionaryService" ref="DictionaryService" />
</bean>
<bean id="baseWorkflowRest" class="org.alfresco.rest.workflow.api.impl.WorkflowRestImpl" abstract="true">

View File

@@ -39,6 +39,7 @@ import org.alfresco.rest.workflow.api.model.VariableScope;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -60,6 +61,8 @@ public class RestVariableHelper
private WorkflowQNameConverter qNameConverter;
private DictionaryService dictionaryService;
public static final Set<String> INTERNAL_PROPERTIES = new HashSet<String>(Arrays.asList(ActivitiConstants.VAR_TENANT_DOMAIN));
public void setNodeService(NodeService nodeService)
@@ -72,6 +75,11 @@ public class RestVariableHelper
this.namespaceService = namespaceService;
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
protected WorkflowQNameConverter getQNameConverter()
{
if (qNameConverter == null)
@@ -174,6 +182,17 @@ public class RestVariableHelper
{
// Not defined as a property, check if it's an association
AssociationDefinition assocDef = context.getAssociationDefinition(variable.getName());
if (assocDef == null)
{
// Try to get an association definition through dictionary
String[] prefixLocalName = variable.getName().split("_");
if (prefixLocalName.length == 2)
{
QName qName = QName.createQName(prefixLocalName[0], prefixLocalName[1], namespaceService);
assocDef = dictionaryService.getAssociation(qName);
}
}
if (assocDef != null)
{
// Type of variable is the target class-name
@@ -182,8 +201,7 @@ public class RestVariableHelper
}
else
{
// Variable is not a declared property not association on the type-definition. Revert to using the actual raw value
// as base for conversion.
// Variable is not declared as property or association type-def. Use actual raw value as base for conversion.
variable.setValue(getSafePropertyValue(value));
variable.setType(extractTypeStringFromValue(value));
}

View File

@@ -486,6 +486,109 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
}
}
/*
* Test association definition extraction from the dictionary as per MNT-11472.
*
* We are going to test association definition extraction through dictionary, when one is not retrieved in context.
* Context doesn't contains all type definitions, because it requires entire history extraction of a process that causes performance implications.
* Type definition extraction from the dictionary is quite fast and it doesn't affect performance.
*
*/
@Test
@SuppressWarnings("unchecked")
public void testAssociationDefinitionExtraction() throws Exception
{
RequestContext requestContext = initApiClientWithTestUser();
// The "wbpm:delegatee" custom association is defined in bpmDelegateeModel.xml. This association has "cm:person" target type.
final String delegatee = "wbpm_delegatee";
final String user = requestContext.getRunAsUser();
final String networkId = requestContext.getNetworkId();
// Get person
final ActivitiScriptNode person = TenantUtil.runAsUserTenant(new TenantRunAsWork<ActivitiScriptNode>()
{
@Override
public ActivitiScriptNode doWork() throws Exception
{
return getPersonNodeRef(user);
}
}, user, networkId);
// Start custom process instance
ProcessInstance processInstance = TenantUtil.runAsUserTenant(new TenantRunAsWork<ProcessInstance>()
{
@Override
public ProcessInstance doWork() throws Exception
{
deployProcessDefinition("workflow/testCustomDelegatee.bpmn20.xml");
String processDefinitionKey = "@" + networkId + "@myProcess";
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("bpm_assignee", person);
variables.put("wf_notifyMe", Boolean.FALSE);
variables.put(WorkflowConstants.PROP_INITIATOR, person);
return activitiProcessEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey, "myProcessKey", variables);
}
}, user, networkId);
// Get task
Task activeTask = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
assertNotNull(activeTask);
try
{
TasksClient tasksClient = publicApiClient.tasksClient();
// Define the "wbpm_delegatee" variable for the taskDefine delegatee user name. POST request will be executed.
JSONArray variablesArray = new JSONArray();
JSONObject variableBody = new JSONObject();
variableBody.put("name", delegatee);
variableBody.put("value", user);
variableBody.put("scope", "local");
variablesArray.add(variableBody);
try
{
// Set variable for the task.
JSONObject response = tasksClient.createTaskVariables(activeTask.getId(), variablesArray);
assertNotNull(response);
JSONObject variable = (JSONObject) response.get("entry");
assertEquals(delegatee, variable.get("name"));
// Check that d:noderef type was returned with appropriate nodeRef Id value.
assertEquals("d:noderef", variable.get("type"));
assertEquals(person.getNodeRef().getId(), variable.get("value"));
// Get process variables. GET request will be executed.
response = publicApiClient.processesClient().getProcessvariables(processInstance.getId());
assertNotNull(response);
assertTrue(delegatee + " variable was not set", response.toJSONString().contains(delegatee));
JSONArray entries = (JSONArray) response.get("entries");
// Find "wbpm_delegatee" variable.
for (Object entry : entries)
{
variable = (JSONObject) ((JSONObject) entry).get("entry");
if (variable.get("name").equals(delegatee))
{
// Check that type corresponds to the target class.
// It means that assoc type def was retrieved successfully from the dictionary.
assertEquals("cm:person", variable.get("type"));
// Value should be an actual user name.
assertEquals(user, variable.get("value"));
}
}
}
catch (PublicApiException ex)
{
fail("Unexpected result " + ex);
}
}
finally
{
cleanupProcessInstance(processInstance);
}
}
@Test
@SuppressWarnings("unchecked")
public void testUpdateTaskAuthorization() throws Exception

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.alfresco.org/model/dictionary/1.0 ../../../../webapps/alfresco/WEB-INF/classes/alfresco/model/modelSchema.xsd"
xmlns="http://www.alfresco.org/model/dictionary/1.0" name="wbpm:AssigneeTest">
<description>BPM Assignee Test Model</description>
<author>Workdesk</author>
<version>1.0</version>
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/bpm/1.0" prefix="bpm"/>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
</imports>
<namespaces>
<namespace uri="workdesk.alf.bpm" prefix="wbpm"/>
</namespaces>
<constraints>
<constraint name="wbpm:listDelegation" type="LIST">
<parameter name="allowedValues">
<list>
<value>Expression</value>
<value>OnCreate</value>
<value>Other</value>
</list>
</parameter>
</constraint>
</constraints>
<types>
<type name="wbpm:DelegateTask">
<title>Delegation Task (Assignee)</title>
<parent>bpm:workflowTask</parent>
<properties>
<property name="wbpm:nextStep">
<title>Next Step</title>
<type>d:text</type>
<protected>false</protected>
<mandatory>false</mandatory>
<multiple>false</multiple>
<default>Expression</default>
<constraints>
<constraint ref="wbpm:listDelegation" />
</constraints>
</property>
</properties>
<associations>
<association name="wbpm:delegatee">
<title>Responsible person</title>
<source>
<mandatory>false</mandatory>
<many>false</many>
</source>
<target>
<class>cm:person</class>
<mandatory>true</mandatory>
<many>false</many>
</target>
</association>
</associations>
</type>
<type name="wbpm:expressionTask">
<title>Expression Task (Assignee)</title>
<parent>bpm:workflowTask</parent>
<mandatory-aspects>
<aspect>wbpm:CommentAspect</aspect>
</mandatory-aspects>
</type>
<type name="wbpm:onCreateTask">
<title>On Create (Assignee)</title>
<parent>bpm:workflowTask</parent>
<mandatory-aspects>
<aspect>wbpm:CommentAspect</aspect>
</mandatory-aspects>
</type>
<type name="wbpm:otherTask">
<title>Other Task (Assignee)</title>
<parent>bpm:workflowTask</parent>
<mandatory-aspects>
<aspect>wbpm:CommentAspect</aspect>
</mandatory-aspects>
</type>
</types>
<aspects>
<aspect name="wbpm:CommentAspect">
<title>Step Comment</title>
<properties>
<property name="wbpm:comment">
<title>Comment</title>
<type>d:text</type>
<protected>false</protected>
<mandatory>false</mandatory>
<multiple>true</multiple>
</property>
</properties>
</aspect>
</aspects>
</model>

View File

@@ -18,6 +18,7 @@
<property name="models">
<list>
<value>models/custom-model.xml</value>
<value>models/bpmDelegateeModel.xml</value>
</list>
</property>
</bean>

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="myProcess" name="My process" isExecutable="true">
<startEvent id="alfrescoStartEv" name="Start Assignee Process" activiti:formKey="wf:submitAdhocTask"></startEvent>
<userTask id="delegateToAssignee" name="Delegate Task" activiti:candidateGroups="GROUP_ALFRESCO_ADMINISTRATORS" activiti:formKey="wbpm:DelegateTask">
<extensionElements>
<activiti:taskListener event="complete" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string><![CDATA[execution.setVariable('wbpm_nextStep', task.getVariable('wbpm_nextStep'));
execution.setVariable('wbpm_delegatee', task.getVariable('wbpm_delegatee'));]]></activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="flow1" sourceRef="alfrescoStartEv" targetRef="delegateToAssignee"></sequenceFlow>
<exclusiveGateway id="DelegateeGateway" name="Exclusive Gateway" default="otherFlow"></exclusiveGateway>
<sequenceFlow id="flow2" sourceRef="delegateToAssignee" targetRef="DelegateeGateway"></sequenceFlow>
<userTask id="oncreateUT" name="On Create Assignee" activiti:formKey="wbpm:onCreateTask">
<extensionElements>
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string><![CDATA[task.assignee = execution.getVariable("wbpm_delegatee");]]></activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="OnCreateFlow" sourceRef="DelegateeGateway" targetRef="oncreateUT">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${wbpm_nextStep == 'OnCreate'}]]></conditionExpression>
</sequenceFlow>
<userTask id="expressionUT" name="Expression Assignee" activiti:assignee="${wbpm_delegatee.properties.userName}" activiti:formKey="wbpm:expressionTask"></userTask>
<sequenceFlow id="ExpressionFlow" sourceRef="DelegateeGateway" targetRef="expressionUT">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${wbpm_nextStep == 'Expression'}]]></conditionExpression>
</sequenceFlow>
<userTask id="otherUT" name="Default Assgnee Task" activiti:candidateGroups="GROUP_ALFRESCO_ADMINISTRATORS" activiti:formKey="wbpm:otherTask"></userTask>
<sequenceFlow id="otherFlow" sourceRef="DelegateeGateway" targetRef="otherUT"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow3" sourceRef="expressionUT" targetRef="endevent1"></sequenceFlow>
<sequenceFlow id="flow4" sourceRef="oncreateUT" targetRef="endevent1"></sequenceFlow>
<sequenceFlow id="flow5" sourceRef="otherUT" targetRef="endevent1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
<bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
<bpmndi:BPMNShape bpmnElement="alfrescoStartEv" id="BPMNShape_alfrescoStartEv">
<omgdc:Bounds height="35.0" width="35.0" x="170.0" y="190.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="delegateToAssignee" id="BPMNShape_delegateToAssignee">
<omgdc:Bounds height="55.0" width="105.0" x="250.0" y="180.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="DelegateeGateway" id="BPMNShape_DelegateeGateway">
<omgdc:Bounds height="40.0" width="40.0" x="400.0" y="188.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="oncreateUT" id="BPMNShape_oncreateUT">
<omgdc:Bounds height="55.0" width="105.0" x="485.0" y="181.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="expressionUT" id="BPMNShape_expressionUT">
<omgdc:Bounds height="55.0" width="105.0" x="485.0" y="90.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="otherUT" id="BPMNShape_otherUT">
<omgdc:Bounds height="55.0" width="105.0" x="485.0" y="270.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="660.0" y="197.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="205.0" y="207.0"></omgdi:waypoint>
<omgdi:waypoint x="250.0" y="207.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="355.0" y="207.0"></omgdi:waypoint>
<omgdi:waypoint x="400.0" y="208.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="OnCreateFlow" id="BPMNEdge_OnCreateFlow">
<omgdi:waypoint x="440.0" y="208.0"></omgdi:waypoint>
<omgdi:waypoint x="485.0" y="208.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="ExpressionFlow" id="BPMNEdge_ExpressionFlow">
<omgdi:waypoint x="420.0" y="188.0"></omgdi:waypoint>
<omgdi:waypoint x="419.0" y="117.0"></omgdi:waypoint>
<omgdi:waypoint x="485.0" y="117.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="otherFlow" id="BPMNEdge_otherFlow">
<omgdi:waypoint x="420.0" y="228.0"></omgdi:waypoint>
<omgdi:waypoint x="420.0" y="297.0"></omgdi:waypoint>
<omgdi:waypoint x="485.0" y="297.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="537.0" y="145.0"></omgdi:waypoint>
<omgdi:waypoint x="677.0" y="197.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
<omgdi:waypoint x="590.0" y="208.0"></omgdi:waypoint>
<omgdi:waypoint x="660.0" y="214.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
<omgdi:waypoint x="537.0" y="270.0"></omgdi:waypoint>
<omgdi:waypoint x="677.0" y="232.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>