Package org.activiti.workflow.simple.alfresco.conversion

Source Code of org.activiti.workflow.simple.alfresco.conversion.InitializeAlfrescoModelsConversionListener

/* 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.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;

import org.activiti.bpmn.model.EventDefinition;
import org.activiti.bpmn.model.FieldExtension;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.IntermediateCatchEvent;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.ServiceTask;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.bpmn.model.TimerEventDefinition;
import org.activiti.bpmn.model.UserTask;
import org.activiti.workflow.simple.alfresco.conversion.form.AlfrescoFormCreator;
import org.activiti.workflow.simple.alfresco.conversion.script.PropertyReference;
import org.activiti.workflow.simple.alfresco.model.M2Aspect;
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.Extension;
import org.activiti.workflow.simple.alfresco.model.config.Form;
import org.activiti.workflow.simple.alfresco.model.config.FormField;
import org.activiti.workflow.simple.alfresco.model.config.FormFieldControl;
import org.activiti.workflow.simple.alfresco.model.config.FormFieldControlParameter;
import org.activiti.workflow.simple.alfresco.model.config.Module;
import org.activiti.workflow.simple.converter.WorkflowDefinitionConversion;
import org.activiti.workflow.simple.converter.listener.WorkflowDefinitionConversionListener;
import org.activiti.workflow.simple.definition.AbstractConditionStepListContainer;
import org.activiti.workflow.simple.definition.AbstractStepDefinitionContainer;
import org.activiti.workflow.simple.definition.AbstractStepListContainer;
import org.activiti.workflow.simple.definition.FormStepDefinition;
import org.activiti.workflow.simple.definition.ListConditionStepDefinition;
import org.activiti.workflow.simple.definition.ListStepDefinition;
import org.activiti.workflow.simple.definition.StepDefinition;
import org.activiti.workflow.simple.definition.WorkflowDefinition;
import org.activiti.workflow.simple.definition.form.FormDefinition;
import org.activiti.workflow.simple.definition.form.FormPropertyDefinition;
import org.activiti.workflow.simple.definition.form.FormPropertyGroup;
import org.activiti.workflow.simple.definition.form.ReferencePropertyDefinition;

/**
* A {@link WorkflowDefinitionConversionListener} that creates a {@link M2Model} and a {@link Configuration}
* before conversion, that can be used to add any models and configuration needed throughout the conversion.
*
* @author Frederik Heremans
* @author Joram Barrez
*/
public class InitializeAlfrescoModelsConversionListener implements WorkflowDefinitionConversionListener, AlfrescoConversionConstants {

  private static final long serialVersionUID = 1L;
 
  protected AlfrescoFormCreator formCreator;
 
  // Types of ReferencePropertyDefinition that should be ignore for reuse
  protected static final Set<String> IGNORED_REFERENCE_TYPES_REUSE = new HashSet<String>(Arrays.asList(
      AlfrescoConversionConstants.FORM_REFERENCE_DUEDATE,
      AlfrescoConversionConstants.FORM_REFERENCE_PRIORITY,
      AlfrescoConversionConstants.FORM_REFERENCE_PACKAGE_ITEMS,
      AlfrescoConversionConstants.FORM_REFERENCE_WORKFLOW_DESCRIPTION
  ));
 
  public InitializeAlfrescoModelsConversionListener() {
    formCreator = new AlfrescoFormCreator();
  }
 
  @Override
  public void beforeStepsConversion(WorkflowDefinitionConversion conversion) {
    String processId = null;
    if(conversion.getWorkflowDefinition().getId() != null) {
      processId = AlfrescoConversionUtil.getValidIdString(conversion.getWorkflowDefinition().getId());
    } else {
      processId = generateUniqueProcessId(conversion);
    }
   
    M2Model model = addContentModel(conversion, processId);
    addExtension(conversion, processId);
   
    // In case the same property definitions are used across multiple forms, we need to identify this
    // up-front and create an aspect for this that can be shared due to the fact that you cannot define the same
    // property twice in a the same content-model namespace
    addAspectsForReusedProperties(conversion.getWorkflowDefinition(), model, processId);
   
    // Add list of property references
    conversion.setArtifact(ARTIFACT_PROPERTY_REFERENCES, new ArrayList<PropertyReference>());
  }

  @Override
  public void afterStepsConversion(WorkflowDefinitionConversion conversion) {
    M2Model model = AlfrescoConversionUtil.getContentModel(conversion);
    M2Namespace modelNamespace = model.getNamespaces().get(0);
   
    for(FlowElement flowElement : conversion.getProcess().getFlowElements()) {
      if(flowElement instanceof StartEvent) {
        StartEvent startEvent = (StartEvent) flowElement;
        if(startEvent.getFormKey() == null) {
         
          Module module = AlfrescoConversionUtil.getExtension(conversion).getModules().get(0);
          Configuration detailsForm = module.addConfiguration(EVALUATOR_STRING_COMPARE,
              MessageFormat.format(EVALUATOR_CONDITION_ACTIVITI, conversion.getProcess().getId()));
         
          // No form-key is set, either use the default or generate of start-form if this
          // is available
          if(conversion.getWorkflowDefinition().getStartFormDefinition() != null
              && !conversion.getWorkflowDefinition().getStartFormDefinition().getFormGroups().isEmpty()) {
           
            // Create the content model for the start-task
            M2Type type = new M2Type();
         
            model.getTypes().add(type);
            type.setName(AlfrescoConversionUtil.getQualifiedName(modelNamespace.getPrefix(),
                AlfrescoConversionConstants.START_TASK_SIMPLE_NAME));
            type.setParentName(AlfrescoConversionConstants.DEFAULT_START_FORM_TYPE);
           
            // Create a form-config for the start-task
            Module shareModule = AlfrescoConversionUtil.getExtension(conversion).getModules().get(0);
            Configuration configuration = shareModule.addConfiguration(AlfrescoConversionConstants.EVALUATOR_TASK_TYPE
                , type.getName());
            Form formConfig = configuration.createForm();
            formConfig.setStartForm(true);
           
            // Populate model and form based on FormDefinition
            formCreator.createForm(type, formConfig, conversion.getWorkflowDefinition().getStartFormDefinition(), conversion);
           
            // Use the same form-config for the workflow details
            detailsForm.addForm(formConfig);
           
            // Set formKey on start-event, referencing type
            startEvent.setFormKey(type.getName());
          } else {
            // Revert to the default start-form
            startEvent.setFormKey(DEFAULT_START_FORM_TYPE);
           
            // Also add form-config to the share-module for workflow detail screen, based on the default form
            populateDefaultDetailFormConfig(detailsForm);
          }
         
        }
      }
    }
   
   

    // Check all elements that can contain PropertyReferences or need additional builders invoked
    List<PropertyReference> references = AlfrescoConversionUtil.getPropertyReferences(conversion);
    for(FlowElement element : conversion.getProcess().getFlowElements()) {
      if(element instanceof SequenceFlow) {
        resolvePropertyRefrencesInSequenceFlow((SequenceFlow) element, modelNamespace, references);
      } else if(element instanceof IntermediateCatchEvent) {
        resolvePropertyRefrencesInCatchEvent((IntermediateCatchEvent) element, modelNamespace, references);
      } else if(element instanceof ServiceTask)  {
        resolvePropertyRefrencesInServiceTask((ServiceTask) element, modelNamespace, references);
      } else if(element instanceof UserTask) {
        addScriptListenersToUserTask((UserTask) element, conversion);
      }
    }
   
    // Check if all property-references reference a valid property
    if(references != null && !references.isEmpty()) {
      for(PropertyReference reference : references) {
        reference.validate(model);
      }
    }
   
  }
 
  protected void addScriptListenersToUserTask(UserTask userTask, WorkflowDefinitionConversion conversion) {
    // Add create-script-listener if it has been used in this conversion
    if(AlfrescoConversionUtil.hasTaskScriptTaskListenerBuilder(conversion, userTask.getId(),
        AlfrescoConversionConstants.TASK_LISTENER_EVENT_CREATE)) {
      userTask.getTaskListeners().add(AlfrescoConversionUtil.getScriptTaskListenerBuilder(conversion, userTask.getId(),
          AlfrescoConversionConstants.TASK_LISTENER_EVENT_CREATE).build());
    }
   
    // Add complete-script-listener if it has been used in this conversion
    if(AlfrescoConversionUtil.hasTaskScriptTaskListenerBuilder(conversion, userTask.getId(),
        AlfrescoConversionConstants.TASK_LISTENER_EVENT_COMPLETE)) {
      userTask.getTaskListeners().add(AlfrescoConversionUtil.getScriptTaskListenerBuilder(conversion, userTask.getId(),
          AlfrescoConversionConstants.TASK_LISTENER_EVENT_COMPLETE).build());
    }
  }
 
  protected void resolvePropertyRefrencesInSequenceFlow(SequenceFlow sequenceFlow, M2Namespace modelNamespace, List<PropertyReference> references) {
    if(sequenceFlow.getConditionExpression() != null && PropertyReference.containsPropertyReference(sequenceFlow.getConditionExpression())) {
      sequenceFlow.setConditionExpression(PropertyReference.replaceAllPropertyReferencesInString(sequenceFlow.getConditionExpression(), modelNamespace.getPrefix(), references, false));
    }
  }
 
  protected void resolvePropertyRefrencesInCatchEvent(IntermediateCatchEvent event, M2Namespace modelNamespace, List<PropertyReference> references) {
    if(event.getEventDefinitions() != null && !event.getEventDefinitions().isEmpty()) {
      for(EventDefinition def : event.getEventDefinitions()) {
        if(def instanceof TimerEventDefinition) {
          TimerEventDefinition timer = (TimerEventDefinition) def;
          if(timer.getTimeDate() != null && PropertyReference.isPropertyReference(timer.getTimeDate())) {
            timer.setTimeDate(PropertyReference.createReference(timer.getTimeDate()).getPropertyReferenceExpression(modelNamespace.getPrefix()));
          }
        }
      }
    }
  }
 
  protected void resolvePropertyRefrencesInServiceTask(ServiceTask serviceTask, M2Namespace modelNamespace, List<PropertyReference> references) {
    if(serviceTask.getFieldExtensions() != null && !serviceTask.getFieldExtensions().isEmpty()) {
      for(FieldExtension extension : serviceTask.getFieldExtensions()) {
        String value = extension.getExpression();
        if(value != null && !value.isEmpty() && PropertyReference.containsPropertyReference(value)) {
          value = PropertyReference.replaceAllPropertyReferencesInString(value, modelNamespace.getPrefix(), references, true);
          extension.setExpression(value);
        }
      }
    }
  }
 
 
 
  protected String generateUniqueProcessId(WorkflowDefinitionConversion conversion) {
    String processId = AlfrescoConversionUtil.getValidIdString(
        PROCESS_ID_PREFIX + UUID.randomUUID().toString());
    conversion.getProcess().setId(processId);
    return processId;
  }
 
  protected void addAspectsForReusedProperties(WorkflowDefinition workflowDefinition, M2Model model, String processId) {
    Map<String, FormPropertyDefinition> definitionMap = new HashMap<String, FormPropertyDefinition>();
   
    // Add start-form properties
    addDefinitionsToMap(workflowDefinition.getStartFormDefinition(), definitionMap);
   
    // Run through steps recursivelye, looking for properties
    addAspectsForReusedProperties(workflowDefinition.getSteps(), model, processId, definitionMap);
   
    // Check if the map contains values other than null, this indicates duplicate properties are found
    for(Entry<String, FormPropertyDefinition> entry : definitionMap.entrySet()) {
      if(entry.getValue() != null) {
        // Create an aspect for this property. The aspect itself will be populated when the first
        // property is converted with that name
        M2Aspect aspect = new M2Aspect();
        aspect.setName(AlfrescoConversionUtil.getQualifiedName(processId, entry.getKey()));
        model.getAspects().add(aspect);
      }
    }
  }

  @SuppressWarnings({ "rawtypes", "unchecked" })
  protected void addAspectsForReusedProperties(List<StepDefinition> steps, M2Model model, String processId, Map<String, FormPropertyDefinition> definitionMap) {
    for (StepDefinition step : steps) {
      if (step instanceof FormStepDefinition) {
        addDefinitionsToMap(((FormStepDefinition) step).getForm(), definitionMap);
      } else if(step instanceof AbstractStepListContainer<?>) {
        List<ListStepDefinition<?>> stepList = ((AbstractStepListContainer) step).getStepList();
        for(ListStepDefinition<?> list : stepList) {
          addAspectsForReusedProperties(list.getSteps(), model, processId, definitionMap);
        }
      } else if(step instanceof AbstractConditionStepListContainer<?>) {
        List<ListConditionStepDefinition<?>> stepList = ((AbstractConditionStepListContainer) step).getStepList();
        for(ListConditionStepDefinition<?> list : stepList) {
          addAspectsForReusedProperties(list.getSteps(), model, processId, definitionMap);
        }
      } else if(step instanceof AbstractStepDefinitionContainer<?>) {
        addAspectsForReusedProperties(((AbstractStepDefinitionContainer<WorkflowDefinition>) step).getSteps(), model, processId, definitionMap);
      }
    }
  }
 
  protected void addDefinitionsToMap(FormDefinition formDefinition, Map<String, FormPropertyDefinition> definitionMap) {
    if(formDefinition != null && formDefinition.getFormGroups() != null) {
      String finalPropertyName = null;
      for(FormPropertyGroup group : formDefinition.getFormGroups()) {
        if(group.getFormPropertyDefinitions() != null) {
          for(FormPropertyDefinition def : group.getFormPropertyDefinitions()) {
            if(isPropertyReuseCandidate(def)) {
              finalPropertyName = AlfrescoConversionUtil.getValidIdString(def.getName());
              if(definitionMap.containsKey(finalPropertyName)) {
                definitionMap.put(finalPropertyName, def);
              } else {
                definitionMap.put(finalPropertyName, null);
              }
            }
          }
        }
      }
    }
  }
 
  protected boolean isPropertyReuseCandidate(FormPropertyDefinition def) {
    boolean valid = !(def instanceof ReferencePropertyDefinition);
    if(!valid) {
      ReferencePropertyDefinition reference = (ReferencePropertyDefinition) def;
      valid = ! IGNORED_REFERENCE_TYPES_REUSE.contains(reference.getType());
    }
    return valid;
  }

  protected M2Model addContentModel(WorkflowDefinitionConversion conversion, String processId) {
    // The process ID is used as namespace prefix, to guarantee uniqueness
   
    // Set general model properties
    M2Model model = new M2Model();
    model.setName(AlfrescoConversionUtil.getQualifiedName(processId,
        CONTENT_MODEL_UNQUALIFIED_NAME));
   
    M2Namespace namespace = AlfrescoConversionUtil.createNamespace(processId);
    model.getNamespaces().add(namespace);
   
   
    // Import required alfresco models
    model.getImports().add(DICTIONARY_NAMESPACE);
    model.getImports().add(CONTENT_NAMESPACE);
    model.getImports().add(BPM_NAMESPACE);
   
    // Store model in the conversion artifacts to be accessed later
    AlfrescoConversionUtil.storeContentModel(model, conversion);
    AlfrescoConversionUtil.storeModelNamespacePrefix(namespace.getPrefix(), conversion);
   
    return model;
  }
 
  protected void addExtension(WorkflowDefinitionConversion conversion, String processId) {
    // Create form-configuration
    Extension extension = new Extension();
    Module module = new Module();
    extension.addModule(module);
    module.setId(MessageFormat.format(MODULE_ID, processId));
    AlfrescoConversionUtil.storeExtension(extension, conversion);
  }
 
  protected void populateDefaultDetailFormConfig(Configuration configuration) {
    Form form = configuration.createForm();
   
    // Add visibility of fields
    form.getFormFieldVisibility().addShowFieldElement(PROPERTY_WORKFLOW_DESCRIPTION);
    form.getFormFieldVisibility().addShowFieldElement(PROPERTY_WORKFLOW_DUE_DATE);
    form.getFormFieldVisibility().addShowFieldElement(PROPERTY_WORKFLOW_PRIORITY);
    form.getFormFieldVisibility().addShowFieldElement(PROPERTY_PACKAGEITEMS);
    form.getFormFieldVisibility().addShowFieldElement(PROPERTY_SEND_EMAIL_NOTIFICATIONS);
   
    // Add all sets to the appearance
    form.getFormAppearance().addFormSet(FORM_SET_GENERAL, FORM_SET_APPEARANCE_TITLE, FORM_SET_GENERAL_LABEL, null);
    form.getFormAppearance().addFormSet(FORM_SET_INFO, null, null, FORM_SET_TEMPLATE_2_COLUMN);
    form.getFormAppearance().addFormSet(FORM_SET_ASSIGNEE, FORM_SET_APPEARANCE_TITLE, FORM_SET_ASSIGNEE_LABEL, null);
    form.getFormAppearance().addFormSet(FORM_SET_ITEMS, FORM_SET_APPEARANCE_TITLE, FORM_SET_ITEMS_LABEL, null);
    form.getFormAppearance().addFormSet(FORM_SET_OTHER, FORM_SET_APPEARANCE_TITLE, FORM_SET_OTHER_LABEL, null);
   
    // Finally, add the individual fields
    FormField descriptionField = new FormField();
    descriptionField.setId(PROPERTY_WORKFLOW_DESCRIPTION);
    descriptionField.setControl(new FormFieldControl(FORM_MULTILINE_TEXT_TEMPLATE));
    descriptionField.setLabelId(FORM_WORKFLOW_DESCRIPTION_LABEL);
    form.getFormAppearance().addFormAppearanceElement(descriptionField);
   
    FormField dueDateField = new FormField();
    dueDateField.setId(PROPERTY_WORKFLOW_DUE_DATE);
    dueDateField.setSet(FORM_SET_INFO);
    dueDateField.setLabelId(FORM_WORKFLOW_DUE_DATE_LABEL);
    dueDateField.setControl(new FormFieldControl(FORM_DATE_TEMPLATE));
    dueDateField.getControl().getControlParameters().add(new FormFieldControlParameter(FORM_DATE_PARAM_SHOW_TIME, Boolean.FALSE.toString()));
    dueDateField.getControl().getControlParameters().add(new FormFieldControlParameter(FORM_DATE_PARAM_SUBMIT_TIME, Boolean.FALSE.toString()));
    form.getFormAppearance().addFormAppearanceElement(dueDateField);
   
    FormField priorityField = new FormField();
    priorityField.setSet(FORM_SET_INFO);
    priorityField.setLabelId(FORM_WORKFLOW_PRIORITY_LABEL);
    priorityField.setId(PROPERTY_WORKFLOW_PRIORITY);
    priorityField.setControl(new FormFieldControl(FORM_PRIORITY_TEMPLATE));
    form.getFormAppearance().addFormAppearanceElement(priorityField);
   
    form.getFormAppearance().addFormField(PROPERTY_PACKAGEITEMS, null, FORM_SET_ITEMS);
   
    FormField emailNotificationsField = new FormField();
    emailNotificationsField.setSet(FORM_SET_OTHER);
    emailNotificationsField.setId(PROPERTY_SEND_EMAIL_NOTIFICATIONS);
    emailNotificationsField.setControl(new FormFieldControl(FORM_EMAIL_NOTIFICATION_TEMPLATE));
    form.getFormAppearance().addFormAppearanceElement(emailNotificationsField);
  }
}
TOP

Related Classes of org.activiti.workflow.simple.alfresco.conversion.InitializeAlfrescoModelsConversionListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.