/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.workflow.simple.alfresco.conversion;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.UserTask;
import org.activiti.workflow.simple.alfresco.conversion.exception.AlfrescoSimpleWorkflowException;
import org.activiti.workflow.simple.alfresco.conversion.form.AlfrescoFormCreator;
import org.activiti.workflow.simple.alfresco.conversion.script.PropertyReference;
import org.activiti.workflow.simple.alfresco.conversion.script.ScriptTaskListenerBuilder;
import org.activiti.workflow.simple.alfresco.model.M2Model;
import org.activiti.workflow.simple.alfresco.model.M2Namespace;
import org.activiti.workflow.simple.alfresco.model.M2Type;
import org.activiti.workflow.simple.alfresco.model.config.Configuration;
import org.activiti.workflow.simple.alfresco.model.config.Form;
import org.activiti.workflow.simple.alfresco.model.config.Module;
import org.activiti.workflow.simple.converter.WorkflowDefinitionConversion;
import org.activiti.workflow.simple.converter.step.HumanStepDefinitionConverter;
import org.activiti.workflow.simple.converter.step.StepDefinitionConverter;
import org.activiti.workflow.simple.definition.HumanStepAssignment.HumanStepAssignmentType;
import org.activiti.workflow.simple.definition.HumanStepDefinition;
import org.activiti.workflow.simple.definition.StepDefinition;
import org.activiti.workflow.simple.exception.SimpleWorkflowException;
/**
* A {@link StepDefinitionConverter} which adds a content-model and a form-config to the conversion
* based on the {@link HumanStepDefinition} that is converted.
*
* @author Frederik Heremans
*/
public class AlfrescoHumanStepDefinitionConverter extends HumanStepDefinitionConverter {
private static final long serialVersionUID = 1L;
private AlfrescoFormCreator formCreator;
public AlfrescoHumanStepDefinitionConverter() {
formCreator = new AlfrescoFormCreator();
}
@Override
public Class<? extends StepDefinition> getHandledClass() {
return HumanStepDefinition.class;
}
@Override
public UserTask convertStepDefinition(StepDefinition stepDefinition, WorkflowDefinitionConversion conversion) {
HumanStepDefinition humanStep = (HumanStepDefinition) stepDefinition;
validate(humanStep);
M2Model model = AlfrescoConversionUtil.getContentModel(conversion);
M2Namespace modelNamespace = model.getNamespaces().get(0);
// Let superclass handle BPMN-specific conversion
UserTask userTask = super.convertStepDefinition(stepDefinition, conversion);
// Clear form-properties in the BPMN file, as we use custom form-mapping in Alfresco
userTask.getFormProperties().clear();
userTask.setName(humanStep.getName() != null ? humanStep.getName() : humanStep.getId());
// Create the content model for the task
M2Type type = new M2Type();
model.getTypes().add(type);
type.setName(AlfrescoConversionUtil.getQualifiedName(modelNamespace.getPrefix(),
humanStep.getId()));
type.setParentName(AlfrescoConversionConstants.DEFAULT_BASE_FORM_TYPE);
// Update task-key on the task itself
userTask.setFormKey(type.getName());
// Create a form-config for the task
Module shareModule = AlfrescoConversionUtil.getExtension(conversion).getModules().get(0);
Configuration configuration = shareModule.addConfiguration(AlfrescoConversionConstants.EVALUATOR_TASK_TYPE
, type.getName());
Form formConfig = configuration.createForm();
// Populate model and form based on FormDefinition
formCreator.createForm(type, formConfig, humanStep.getForm(), conversion);
// Set up property sharing using task-listeners
addPropertySharing(humanStep, conversion, userTask);
// Special handling for assignee that reference form-properties, before BPMN
// is created
if (humanStep.getAssignmentType() == HumanStepAssignmentType.USER) {
String assignee = humanStep.getAssignment().getAssignee();
if (assignee != null && PropertyReference.isPropertyReference(assignee)) {
PropertyReference reference = PropertyReference.createReference(assignee);
AlfrescoConversionUtil.getPropertyReferences(conversion).add(reference);
userTask.setAssignee(reference.getUsernameReferenceExpression(modelNamespace.getPrefix()));
}
} else if (humanStep.getAssignmentType() == HumanStepAssignmentType.USERS) {
if(humanStep.getAssignment().getCandidateUsers() != null) {
userTask.setCandidateUsers(resolveUserPropertyReferences(humanStep.getAssignment().getCandidateUsers(), modelNamespace.getPrefix(), conversion));
}
} else if (humanStep.getAssignmentType() == HumanStepAssignmentType.GROUPS) {
if(humanStep.getAssignment().getCandidateGroups() != null) {
userTask.setCandidateGroups(resolveGroupPropertyReferences(humanStep.getAssignment().getCandidateGroups(), modelNamespace.getPrefix(), conversion));
}
}
return userTask;
}
protected UserTask locateUserTask(WorkflowDefinitionConversion conversion) {
List<FlowElement> elements = (List<FlowElement>) conversion.getProcess().getFlowElements();
for(int i=elements.size() -1; i >= 0; i--) {
if(elements.get(i) instanceof UserTask) {
return (UserTask) elements.get(i);
}
}
throw new SimpleWorkflowException("No usertask found in conversion");
}
protected void addPropertySharing(HumanStepDefinition humanStep, WorkflowDefinitionConversion conversion, UserTask userTask) {
PropertySharing sharing = AlfrescoConversionUtil.getPropertySharing(conversion, userTask.getId());
// Add default incoming properties (due-date and priority)
// TODO: make optional?
ScriptTaskListenerBuilder createEventBuilder = AlfrescoConversionUtil.getScriptTaskListenerBuilder(conversion, userTask.getId(),
AlfrescoConversionConstants.TASK_LISTENER_EVENT_CREATE);
createEventBuilder.addDueDateInheritance();
createEventBuilder.addPriorityInheritance();
// Add create-listener in case incoming properties are present
if(sharing.hasIncomingProperties()) {
createEventBuilder = AlfrescoConversionUtil.getScriptTaskListenerBuilder(conversion, userTask.getId(),
AlfrescoConversionConstants.TASK_LISTENER_EVENT_CREATE);
for(Entry<String, String> entry : sharing.getIncomingProperties().entrySet()) {
createEventBuilder.addIncomingProperty(entry.getKey(), entry.getValue());
}
}
// Add complete-listener in case incoming properties are present
if(sharing.hasOutgoingProperties()) {
ScriptTaskListenerBuilder completeEventBuilder = AlfrescoConversionUtil.getScriptTaskListenerBuilder(conversion, userTask.getId(),
AlfrescoConversionConstants.TASK_LISTENER_EVENT_COMPLETE);
for(Entry<String, String> entry : sharing.getOutgoingProperties().entrySet()) {
completeEventBuilder.addOutgoingProperty(entry.getKey(), entry.getValue());
}
}
}
protected List<String> resolveUserPropertyReferences(List<String> list, String namespacePrefix, WorkflowDefinitionConversion conversion) {
if(list != null) {
List<String> result = new ArrayList<String>();
PropertyReference propertyReference = null;
for(String string : list) {
if(PropertyReference.isPropertyReference(string)) {
propertyReference = PropertyReference.createReference(string);
result.add(propertyReference.getUsernameReferenceExpression(namespacePrefix));
// Add reference to be validated
AlfrescoConversionUtil.getPropertyReferences(conversion).add(propertyReference);
} else {
result.add(string);
}
}
return result;
}
return null;
}
protected List<String> resolveGroupPropertyReferences(List<String> list, String namespacePrefix, WorkflowDefinitionConversion conversion) {
if(list != null) {
List<String> result = new ArrayList<String>();
PropertyReference propertyReference = null;
for(String string : list) {
if(PropertyReference.isPropertyReference(string)) {
propertyReference = PropertyReference.createReference(string);
result.add(propertyReference.getGroupReferenceExpression(namespacePrefix));
// Add reference to be validated
AlfrescoConversionUtil.getPropertyReferences(conversion).add(propertyReference);
} else {
result.add(string);
}
}
return result;
}
return null;
}
@Override
protected String getInitiatorExpression() {
// Use the correct assignee expression if the initiator is used for assignment
return AlfrescoConversionConstants.INITIATOR_ASSIGNEE_EXPRESSION;
}
@Override
protected String getInitiatorVariable() {
// Variable used to store the assignee
return AlfrescoConversionConstants.INITIATOR_VARIABLE;
}
protected void validate(HumanStepDefinition stepDefinition) {
if(stepDefinition.getId() == null) {
if(stepDefinition.getName() == null && !stepDefinition.getName().isEmpty()) {
throw new AlfrescoSimpleWorkflowException("Name or id of a human step is required.");
}
stepDefinition.setId(AlfrescoConversionUtil.getValidIdString(stepDefinition.getName()));
}
}
}