工作流系列(5.3)-Activiti流程文件解析-解析扩展

文章目录

    • 解析扩展元素
    • 解析自定义属性
    • 解析子元素

解析扩展元素

之前我们看的都是Activiti对自有元素的解析,比如UserTask、Process、StartEvent等,而在Activiti中,我们也可以对自定义元素进行解析。对自定义元素的解析是通过org.activiti.bpmn.converter.util.BpmnXMLUtil.parseExtensionElement进行解析的。解析代码如下

public static ExtensionElement parseExtensionElement(XMLStreamReader xtr) throws Exception {
    ExtensionElement extensionElement = new ExtensionElement();
    extensionElement.setName(xtr.getLocalName());
    if (StringUtils.isNotEmpty(xtr.getNamespaceURI())) {
      extensionElement.setNamespace(xtr.getNamespaceURI());
    }
    if (StringUtils.isNotEmpty(xtr.getPrefix())) {
      extensionElement.setNamespacePrefix(xtr.getPrefix());
    }

    for (int i = 0; i < xtr.getAttributeCount(); i++) {
      ExtensionAttribute extensionAttribute = new ExtensionAttribute();
      extensionAttribute.setName(xtr.getAttributeLocalName(i));
      extensionAttribute.setValue(xtr.getAttributeValue(i));
      if (StringUtils.isNotEmpty(xtr.getAttributeNamespace(i))) {
        extensionAttribute.setNamespace(xtr.getAttributeNamespace(i));
      }
      if (StringUtils.isNotEmpty(xtr.getAttributePrefix(i))) {
        extensionAttribute.setNamespacePrefix(xtr.getAttributePrefix(i));
      }
      extensionElement.addAttribute(extensionAttribute);
    }

    boolean readyWithExtensionElement = false;
    while (readyWithExtensionElement == false && xtr.hasNext()) {
      xtr.next();
      if (xtr.isCharacters() || XMLStreamReader.CDATA == xtr.getEventType()) {
        if (StringUtils.isNotEmpty(xtr.getText().trim())) {
          extensionElement.setElementText(xtr.getText().trim());
        }
      } else if (xtr.isStartElement()) {
        ExtensionElement childExtensionElement = parseExtensionElement(xtr);
        extensionElement.addChildElement(childExtensionElement);
      } else if (xtr.isEndElement() && extensionElement.getName().equalsIgnoreCase(xtr.getLocalName())) {
        readyWithExtensionElement = true;
      }
    }
    return extensionElement;
  }
  1. 首先实例化扩展元素,以便获取定义的信息
  2. 设置名称、命名空间、命名空间前缀、定义的属性(名称、命名空间、命名空间前缀)
  3. 判断是否结束,
    1. 没有结束则再依次判断
    2. 有文本节点,进行赋值
    3. 有子节点,则获取子节点属性
    4. 是对应的结束节点,跳出循环

比如说如下配置


<definitions
        xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
        xmlns:activiti="http://activiti.org/bpmn"
        targetNamespace="Examples">
      <process id="test-worlfow" name="流程测试"  activiti:key="${bussneKey}" activiti:processHandler="defaultTaskService">
		<extensionElements>
			<activiti:page url="ccccc">activiti:page>
            <activiti:bizConfig>
                <item key="bizType" value="authorize"/>
            activiti:bizConfig>
		extensionElements>      
        <startEvent id="theStart" />
        <sequenceFlow id="flow1" sourceRef="theStart" targetRef="userTask1" />
        <userTask id="userTask1" name="任务1" >
        <extensionElements>  
         	<activiti:toolbar >
         		<activiti:button type="general" name="submit" displayName="提交" targetRef="agree" enable="true">
         			<activiti:user policy="role" para="000100" enable="${true}">activiti:user>
         	 activiti:button>
         	activiti:toolbar>
         	<activiti:bizConfig>
                <item key="stepType" value="待提交"/>
                <item key="other" value="xxx"/>
            activiti:bizConfig>
         	<activiti:page url="/law/${1}.json?">activiti:page>
         extensionElements>
        userTask>
        <sequenceFlow id="flow2" sourceRef="userTask1" targetRef="theEnd" />
        <endEvent id="theEnd" />
    process>

definitions>

以下是测试解析扩展元素的方法

public class TestParseExtensionElement {

    public static void main(String[] args) {
        String resource = "test-workflow.bpmn20.xml";
        InputStream xmlStream = TestParseExtensionElement.class.getClassLoader()
                .getResourceAsStream(resource);
        InputStreamSource xmlSource = new InputStreamSource(xmlStream);
        BpmnXMLConverter converter = new BpmnXMLConverter();
        BpmnModel model = converter.convertToBpmnModel(xmlSource, true, true);
        Process process = model.getMainProcess();
        Map<String, List<ExtensionElement>> extensionElements = process.getExtensionElements();
        displayElementAndChild(extensionElements);
    }

    private static void displayElementAndChild(
            Map<String, List<ExtensionElement>> extensionElements) {
        for (Entry<String, List<ExtensionElement>> entry : extensionElements.entrySet()) {
            List<ExtensionElement> values = entry.getValue();
            for (ExtensionElement e : values) {
                System.out.println("key : " + e.getName());
                displayAttribute(e);
                Map<String, List<ExtensionElement>> child = e.getChildElements();
                if (child == null || child.isEmpty()) {
                    continue;
                }
                displayElementAndChild(child);
            }
        }
    }

    private static void displayAttribute(ExtensionElement extensionElement) {
        Map<String, List<ExtensionAttribute>> attributes = extensionElement.getAttributes();
        Collection<List<ExtensionAttribute>> attrValues = attributes.values();
        if (attrValues == null || attrValues.isEmpty()) {
            return;
        }
        System.out.println(extensionElement.getName() + " attributes:");
        System.out.print("\t");
        for (List<ExtensionAttribute> list : attrValues) {
            for (ExtensionAttribute attr : list) {
                System.out.print(attr.getName() + ":" + attr.getValue() + ", ");
            }
        }
        System.out.println();
    }

}
  1. 首先我们读取上文中提到的流程配置文件
  2. 调用BpmnXMLConverter中的converToBpmnModel方法获取BpmnModel对象
  3. displayElementAndChild方法打印输出元素以及子元素的信息
  4. displayAttribute方法输出自定义属性信息

解析自定义属性

在之前的的几个转换类中,我们发现大部分都有要解析自定义属性,可以简单看一下对自定义属性的解析,在org.activiti.bpmn.converter.util.BpmnXMLUtil类中,

 /**
   * 将所有的扩展属性添加到元素中,并忽略blackLists中的扩展属性
   * 
   * @param xtr
   * @param element
   * @param blackList 黑名单
   */
  public static void addCustomAttributes(XMLStreamReader xtr, BaseElement element, List... blackLists) {
    for (int i = 0; i < xtr.getAttributeCount(); i++) {
      ExtensionAttribute extensionAttribute = new ExtensionAttribute();
      extensionAttribute.setName(xtr.getAttributeLocalName(i));
      extensionAttribute.setValue(xtr.getAttributeValue(i));
      if (StringUtils.isNotEmpty(xtr.getAttributeNamespace(i))) {
        extensionAttribute.setNamespace(xtr.getAttributeNamespace(i));
      }
      if (StringUtils.isNotEmpty(xtr.getAttributePrefix(i))) {
        extensionAttribute.setNamespacePrefix(xtr.getAttributePrefix(i));
      }
      if (!isBlacklisted(extensionAttribute, blackLists)) {
        element.addAttribute(extensionAttribute);
      }
    }
  }
  1. 解析扩展属性比较简单,基本逻辑就是将name、value、namespace等属性解析
  2. 忽略黑名单中的属性

黑名单属性

  1. 全局属性
    | 属性| 含义|
    | – | --|
    | id |id,全局唯一 |
    | name|任务节点的名称 |

  2. activiti属性
    | 属性| 命名空间 | 含义|
    | – | --| --|
    | aysn|http://activiti.org/bpmn|是否异步执行|
    | exclusive|http://activiti.org/bpmn|是否排他|
    | default||默认属性|
    | isForCompensation|http://activiti.org/bpmn|是否补偿|

  3. 元素特有属性(userTask的属性,process特有的属性)

UserTask特有属性,其命名空间都是http://activiti.org/bpmn

属性 含义
formKey 任务节点关联的form表单
dueDate 任务截止日期
businessCalendarName 业务日历名称
assignee 任务执行人
owner 任务所有者
priority 优先级
candidateUsers 候选执行人
candidateGroups 候选执行人分钟
category 分类
extensionId 扩展id
skipExpression 跳过任务表达式

Process属性,除了公共属性,之外还有一下属性,其命名空间都是http://activiti.org/bpmn

属性 含义
isExecutable 是否可执行单
candidateStarterUsers 候选流程启动执行人
candidateStarterGroups 候选流程启动分组

解析子元素

各个元素的转换器首先会调用抽象类BaseBpmnXMLConverter中的parseChildElements方法

 protected void parseChildElements(String elementName, BaseElement parentElement, BpmnModel model, XMLStreamReader xtr) throws Exception {
    parseChildElements(elementName, parentElement, null, model, xtr);
  }

  protected void parseChildElements(String elementName, BaseElement parentElement, Map additionalParsers, BpmnModel model, XMLStreamReader xtr) throws Exception {

    Map childParsers = new HashMap();
    if (additionalParsers != null) {
      childParsers.putAll(additionalParsers);
    }
    BpmnXMLUtil.parseChildElements(elementName, parentElement, xtr, childParsers, model);
  }

然后再调用org.activiti.bpmn.converter.util.BpmnXMLUtil.parseChildElements方法,

 public static void parseChildElements(String elementName, BaseElement parentElement, XMLStreamReader xtr, 
      Map<String, BaseChildElementParser> childParsers, BpmnModel model) throws Exception {
    
    Map<String, BaseChildElementParser> localParserMap =
        new HashMap<String, BaseChildElementParser>(genericChildParserMap);
    if (childParsers != null) {
      localParserMap.putAll(childParsers);
    }

    boolean inExtensionElements = false;
    boolean readyWithChildElements = false;
    while (readyWithChildElements == false && xtr.hasNext()) {
      xtr.next();
      if (xtr.isStartElement()) {
        if (ELEMENT_EXTENSIONS.equals(xtr.getLocalName())) {
          inExtensionElements = true;
        } else if (localParserMap.containsKey(xtr.getLocalName())) {
          BaseChildElementParser childParser = localParserMap.get(xtr.getLocalName());
          //if we're into an extension element but the current element is not accepted by this parentElement then is read as a custom extension element
          if (inExtensionElements && !childParser.accepts(parentElement)) {
            ExtensionElement extensionElement = BpmnXMLUtil.parseExtensionElement(xtr);
            parentElement.addExtensionElement(extensionElement);
            continue;
          }
          localParserMap.get(xtr.getLocalName()).parseChildElement(xtr, parentElement, model);
        } else if (inExtensionElements) {
          ExtensionElement extensionElement = BpmnXMLUtil.parseExtensionElement(xtr);
          parentElement.addExtensionElement(extensionElement);
        }

      } else if (xtr.isEndElement()) {
        if (ELEMENT_EXTENSIONS.equals(xtr.getLocalName())) {
          inExtensionElements = false;
        } else if (elementName.equalsIgnoreCase(xtr.getLocalName())) {
          readyWithChildElements = true;
        }
      }
    }
  }

通过以上源码我们可以看到解析子元素的步骤

  1. 首先初始化子元素解析器集合,包括通用的子元素的解析器以及每个元素单独适用的的子元素解析器
  2. 解析扩展元素
    a) 如果判断元素属于子元素解析器集合中的类,则直接调用子元素解析
    b) 如果元素是扩展元素(extensionElement),则调用BpmnXMLUtil.parseExtensionElement(xtr)进行解析
  3. 有一个额外判断,如果该元素是扩展元素,并且父类不能接受这个扩展元素,则它被解析为一个扩展元素

以解析userTask元素为例,
首先在UserTaskXMLConverter类中,加入了如下子元素解析器

	HumanPerformerParser humanPerformerParser = new HumanPerformerParser();
    childParserMap.put(humanPerformerParser.getElementName(), humanPerformerParser);
    PotentialOwnerParser potentialOwnerParser = new PotentialOwnerParser();
    childParserMap.put(potentialOwnerParser.getElementName(), potentialOwnerParser);
    CustomIdentityLinkParser customIdentityLinkParser = new CustomIdentityLinkParser();
    childParserMap.put(customIdentityLinkParser.getElementName(), customIdentityLinkParser);

以下是org.activiti.bpmn.converter.UserTaskXMLConverter.convertXMLToElement的部分代码

protected BaseElement convertXMLToElement(XMLStreamReader xtr, BpmnModel model) throws Exception {
    ....
    parseChildElements(getXMLElementName(), userTask, childParserMap, model, xtr);
    return userTask;
  }

可以看出最终会将特有子元素解析器传入并调用父类的方法实现。

你可能感兴趣的:(Activiti学习)