工作流系列(5.2)-Activiti流程文件解析源码分析

解析准备

转换器和解析器共同构建了Activiti的转换基础。

准备转换器

从配置文件的到BpmnModel的转换都是通过org.activiti.bpmn.converterBpmnXMLConvert类来进行,在解析之前会准备各种转换器,具体的代码是

static {
    // events
    addConverter(new EndEventXMLConverter());
    addConverter(new StartEventXMLConverter());

    // tasks
   ....
  }

只列出了部分,没有全部列出。从之前的文章中,我们可以看到对于每个元素都有相对应的转化器(解析器)与其对应,而每个元素公共的属性也有相应的解析器去解析。

解析器

对于各个子元素或公共元素的解析,大部分是通过org.activiti.bpmn.converter.util.BpmnXMLUtil类来进行解析的,当然其也会首先加载不同子元素的解析器。

 static {
    addGenericParser(new ActivitiEventListenerParser());
    ...
    addGenericParser(new IOSpecificationParser());
    addGenericParser(new MessageEventDefinitionParser());
    addGenericParser(new MultiInstanceParser());
    addGenericParser(new SignalEventDefinitionParser());
    addGenericParser(new TaskListenerParser());
    ....
  }

Activiti自有解析

解析入口

在BpmnXMLConvert中,我们使用convertToBpmnModel方法将流程配置文件解析为BpmnModel模型

 public BpmnModel convertToBpmnModel(InputStreamProvider, boolean, boolean)
 public BpmnModel convertToBpmnModel(InputStreamProvider, boolean, boolean, String)
 public BpmnModel convertToBpmnModel(XMLStreamReader)

在解析配置文件过程中,我们需要XML流,有两种方式,

  1. 构建org.activiti.bpmn.converter.util.InputStreamReader
  2. 直接构建XMLStreamReader
    当然最终的处理都是会基于XMLStreamReader

执行解析

我们阅读源码会发现,所有的转换最终都是调用public BpmnModel convertToBpmnModel(XMLStreamReader)方法,我们可以大致浏览一下其方法

public BpmnModel convertToBpmnModel(XMLStreamReader){
    BpmnModel model = new BpmnModel();
    model.setStartEventFormTypes(startEventFormTypes);
    model.setUserTaskFormTypes(userTaskFormTypes);
    try {
	  //定义主流程
      Process activeProcess = null;
      //准备子流程列表
      List<SubProcess> activeSubProcessList = new ArrayList<SubProcess>();
      while (xtr.hasNext()) {
        try {
          xtr.next();
        } catch (Exception e) {
          LOGGER.debug("Error reading XML document", e);
          throw new XMLException("Error reading XML", e);
        }
		//子流程或事务子流程或特别子流程
        if (xtr.isEndElement() && (ELEMENT_SUBPROCESS.equals(xtr.getLocalName()) || 
            ELEMENT_TRANSACTION.equals(xtr.getLocalName()) ||
            ELEMENT_ADHOC_SUBPROCESS.equals(xtr.getLocalName()))) {
          activeSubProcessList.remove(activeSubProcessList.size() - 1);
        }
		//不是开始元素跳过执行
        if (xtr.isStartElement() == false) {
          continue;
        }
        //解析定义信息
        if (ELEMENT_DEFINITIONS.equals(xtr.getLocalName())) {
			 definitionsParser.parse(xtr, model);	  
        } else if (ELEMENT_RESOURCE.equals(xtr.getLocalName())) {
          //解析资源信息
          resourceParser.parse(xtr, model);
         } else if (ELEMENT_SIGNAL.equals(xtr.getLocalName())) {
			signalParser.parse(xtr, model);
		 } else if (ELEMENT_MESSAGE.equals(xtr.getLocalName())) {
            messageParser.parse(xtr, model);
        } else if (ELEMENT_ERROR.equals(xtr.getLocalName())) {
          if (StringUtils.isNotEmpty(xtr.getAttributeValue(null, ATTRIBUTE_ID))) {
            model.addError(xtr.getAttributeValue(null, ATTRIBUTE_ID), xtr.getAttributeValue(null, ATTRIBUTE_ERROR_CODE));
          }
        }
        .....//省略大部分if判断
        } else {
        
          if (!activeSubProcessList.isEmpty() && ELEMENT_MULTIINSTANCE.equalsIgnoreCase(xtr.getLocalName())) {

            multiInstanceParser.parseChildElement(xtr, activeSubProcessList.get(activeSubProcessList.size() - 1), model);

          } else if (convertersToBpmnMap.containsKey(xtr.getLocalName())) {
            if (activeProcess != null) {
              BaseBpmnXMLConverter converter = convertersToBpmnMap.get(xtr.getLocalName());
              converter.convertToBpmnModel(xtr, model, activeProcess, activeSubProcessList);
            }
          }
        }
      }

      for (Process process : model.getProcesses()) {
        for (Pool pool : model.getPools()) {
          if (process.getId().equals(pool.getProcessRef())) {
            pool.setExecutable(process.isExecutable());
          }
        }
        processFlowElements(process.getFlowElements(), process);
      }

    } catch (XMLException e) {
      throw e;

    } catch (Exception e) {
      LOGGER.error("Error processing BPMN document", e);
      throw new XMLException("Error processing BPMN document", e);
    }
    return model;
 } 

通过简单浏览其源码,我们发现是通过对XML文件流进行一系列的判断,根据遇到的元素不同,而调用不同的转化器(解析器),最终将整个BpmnModel构建出来。

探秘转换器(解析器)

因为有很多转化器或解析器,我们不能一一解析,我们将挑选几个比较典型的元素转换器进行分析。对于子元素、扩展元素的解析,放到下一节中。

ProcessParser(流程元素解析)

在convertToBpmnModel方法中,如果遇到Process元素,就会通过调用org.activiti.bpmn.converter.parser.ProcessParser中的parse方法来进行解析

public BpmnModel convertToBpmnModel(XMLStreamReader){
...
   else if (ELEMENT_PROCESS.equals(xtr.getLocalName())) {
      Process process = processParser.parse(xtr, model);
      if (process != null) {
          activeProcess = process;
       }
	}
...
 return model;
}

以下是org.activiti.bpmn.converter.parser.ProcessParser.parse()方法的源码

public Process parse(XMLStreamReader xtr, BpmnModel model) throws Exception {
    //创建Process对象,用于表示该元素
    Process process = null;
    if (StringUtils.isNotEmpty(xtr.getAttributeValue(null, ATTRIBUTE_ID))) {
      //解析processId
      String processId = xtr.getAttributeValue(null, ATTRIBUTE_ID);
      process = new Process();
      process.setId(processId);
      //解析元素在XML文件中的的位置信息
      BpmnXMLUtil.addXMLLocation(process, xtr);
      process.setName(xtr.getAttributeValue(null, ATTRIBUTE_NAME));
      //获取可执行属性
      if (StringUtils.isNotEmpty(xtr.getAttributeValue(null, ATTRIBUTE_PROCESS_EXECUTABLE))) {
        process.setExecutable(Boolean.parseBoolean(xtr.getAttributeValue(null, ATTRIBUTE_PROCESS_EXECUTABLE)));
      }
      //获取流程开始时用户 
      String candidateUsersString = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_PROCESS_CANDIDATE_USERS);
      if (StringUtils.isNotEmpty(candidateUsersString)) {
        List<String> candidateUsers = BpmnXMLUtil.parseDelimitedList(candidateUsersString);
        process.setCandidateStarterUsers(candidateUsers);
      }
      //获取流程开始时分组    
      String candidateGroupsString = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_PROCESS_CANDIDATE_GROUPS);
      if (StringUtils.isNotEmpty(candidateGroupsString)) {
        List<String> candidateGroups = BpmnXMLUtil.parseDelimitedList(candidateGroupsString);
        process.setCandidateStarterGroups(candidateGroups);
      }
	  //解析扩展元素
      BpmnXMLUtil.addCustomAttributes(xtr, process, ProcessExport.defaultProcessAttributes);
      model.getProcesses().add(process);

    }
    return process;
  }
  1. 首先创建Process用于承载解析的对象,如果该元素没有定义id则忽略
  2. 然后元素的id、name等熟悉
  3. 解析扩展属性(会在下方详细介绍)
UserTaskXMLConverter(用户任务转换器)

解析元素userTask时,使用org.activiti.bpmn.converter.UserTaskXMLConverter进行解析。

调用转换器

在BpmnXMLConverter中对其的调用是通过获取转换器Map中对应元素的转化进行解析的。

BaseBpmnXMLConverter converter = convertersToBpmnMap.get(xtr.getLocalName());
converter.convertToBpmnModel(xtr, model, activeProcess, activeSubProcessList);
转换方法
  @Override
  @SuppressWarnings("unchecked")
  protected BaseElement convertXMLToElement(XMLStreamReader xtr, BpmnModel model) throws Exception {
    String formKey = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_FORM_FORMKEY);
    UserTask userTask = null;
    //判断是是否存在formKey(表单key)
    if (StringUtils.isNotEmpty(formKey)) {
      if (model.getUserTaskFormTypes() != null && model.getUserTaskFormTypes().contains(formKey)) {
        userTask = new AlfrescoUserTask();
      }
    }
    if (userTask == null) {
      userTask = new UserTask();
    }
    //解析位置信息
    BpmnXMLUtil.addXMLLocation(userTask, xtr);
    //然后分别解析截止时间,分类,表单key,所属人员,优先级,候选人、候选组、跳过表达式
    userTask.setDueDate(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_DUEDATE));
    userTask.setBusinessCalendarName(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_BUSINESS_CALENDAR_NAME));
    userTask.setCategory(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CATEGORY));
    userTask.setFormKey(formKey);
    userTask.setAssignee(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_ASSIGNEE)); 
    userTask.setOwner(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_OWNER));
    userTask.setPriority(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_PRIORITY));
    
    if (StringUtils.isNotEmpty(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATEUSERS))) {
      String expression = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATEUSERS);
      userTask.getCandidateUsers().addAll(parseDelimitedList(expression));
    } 
    
    if (StringUtils.isNotEmpty(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATEGROUPS))) {
      String expression = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATEGROUPS);
      userTask.getCandidateGroups().addAll(parseDelimitedList(expression));
    }
    
    userTask.setExtensionId(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_SERVICE_EXTENSIONID));

    if (StringUtils.isNotEmpty(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_SKIP_EXPRESSION))) {
      String expression = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_SKIP_EXPRESSION);
      userTask.setSkipExpression(expression);
    }
    //解析自定义属性
    BpmnXMLUtil.addCustomAttributes(xtr, userTask, defaultElementAttributes, 
        defaultActivityAttributes, defaultUserTaskAttributes);
    //解析子元素
    parseChildElements(getXMLElementName(), userTask, childParserMap, model, xtr);
    
    return userTask;
  }

解析用户任务的简要逻辑是:

  1. 首先判断是否存在formKey属性,如果存在则使用则将其解析为AlfrescoUserTask对象,不存在则是UserTask对象
  2. 解析位置信息
  3. 然后分别解析截止时间,分类,表单key,所属人员,优先级,候选人、候选组、跳过表达式
  4. 解析扩展属性
  5. 解析子元素
解析连线(sequenceFlow)

另外一个比较重要的元素是连线,它的解析类是org.activiti.bpmn.converter.SequenceFlowXMLConverter

protected BaseElement convertXMLToElement(XMLStreamReader xtr, BpmnModel model) throws Exception {
    SequenceFlow sequenceFlow = new SequenceFlow();
    BpmnXMLUtil.addXMLLocation(sequenceFlow, xtr);
    sequenceFlow.setSourceRef(xtr.getAttributeValue(null, ATTRIBUTE_FLOW_SOURCE_REF));
    sequenceFlow.setTargetRef(xtr.getAttributeValue(null, ATTRIBUTE_FLOW_TARGET_REF));
    sequenceFlow.setName(xtr.getAttributeValue(null, ATTRIBUTE_NAME));
    sequenceFlow.setSkipExpression(xtr.getAttributeValue(null, ATTRIBUTE_FLOW_SKIP_EXPRESSION));

    parseChildElements(getXMLElementName(), sequenceFlow, model, xtr);

    return sequenceFlow;
  }
  1. 首先实例化SequenceFlow对象,在解析过程中会将相应属性填充进该对象
  2. 解析位置信息
  3. 解析属性,包括sourceRef、targetRef、skipExpression,当然还有常用属性name等
  4. 解析子元素
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值