文章目录
解析准备
转换器和解析器共同构建了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流,有两种方式,
- 构建
org.activiti.bpmn.converter.util.InputStreamReader
- 直接构建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;
}
- 首先创建Process用于承载解析的对象,如果该元素没有定义id则忽略
- 然后元素的id、name等熟悉
- 解析扩展属性(会在下方详细介绍)
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;
}
解析用户任务的简要逻辑是:
- 首先判断是否存在formKey属性,如果存在则使用则将其解析为AlfrescoUserTask对象,不存在则是UserTask对象
- 解析位置信息
- 然后分别解析截止时间,分类,表单key,所属人员,优先级,候选人、候选组、跳过表达式
- 解析扩展属性
- 解析子元素
解析连线(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;
}
- 首先实例化SequenceFlow对象,在解析过程中会将相应属性填充进该对象
- 解析位置信息
- 解析属性,包括sourceRef、targetRef、skipExpression,当然还有常用属性name等
- 解析子元素