Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 |
Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 |
Fixflow引擎解析(二)(模型) - BPMN2.0读写 |
Fixflow引擎解析(一)(介绍) - Fixflow开源流程引擎介绍 |
我们在第一章中介绍了怎么通过EMF读写BPMN2.0官方元素,
第三章中介绍了怎么建立一个简单的EMF模型来读写XML,
在这章里边我们介绍下怎么给BPMN2.0模型注入扩展元素。
1.为什么需要扩展
由于BPMN2.0官方提供的标准不能满足一个引擎需要运行起来的所需的一些元素,所有各个基于BPMN2.0标准的厂商都对BPMN2.0标准进行了自己的扩展。
例如:
activiti引擎的扩展都是以"activiti:"开头的
<serviceTask id="javaService"
name="Java service invocation"
activiti:class="org.activiti.examples.bpmn.servicetask.ToUpperCaseFieldInjected">
<extensionElements>
<activiti:field name="text" stringValue="Hello World" />
</extensionElements>
</serviceTask>
fixflow引擎的扩展都是以"fixflow:"开头的
<bpmn2:userTask id="UserTask_1" fixflow:taskType="FIXFLOWTASK" name="人工任务">
<bpmn2:extensionElements>
<fixflow:assignPolicyType id="potentialOwner"/>
<fixflow:skipStrategy/>
<fixflow:taskCommand id="HandleCommand_3" name="提交" commandType="submit"/>
<fixflow:expectedExecutionTime/>
<fixflow:formUri>
<fixflow:expression xsi:type="fixflow:Expression" id="Expression_3">DemoServlet?action=startOneTask</fixflow:expression>
</fixflow:formUri>
</bpmn2:extensionElements>
<bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_3</bpmn2:outgoing>
<bpmn2:potentialOwner id="PotentialOwner_1" fixflow:resourceType="user" fixflow:includeExclusion="INCLUDE"name="所有人">
<bpmn2:resourceAssignmentExpression id="ResourceAssignmentExpression_1">
<bpmn2:formalExpression id="所有人">"fixflow_allusers"</bpmn2:formalExpression>
</bpmn2:resourceAssignmentExpression>
</bpmn2:potentialOwner>
</bpmn2:userTask>
每个引擎的厂商都会对BPMN2.0官方元素做出扩展,这就导致了流程定义虽然可以在不同的流程产品相互显示,但是想运行起来是不可能的。
2.BPMN2.0官方关于扩展元素的支持
可以看到BPMN2.0官方已经提供了扩展元素的存放位置:
<bpmn2:userTask id="UserTask_1" fixflow:taskType="FIXFLOWTASK" name="人工任务">
<bpmn2:extensionElements>
<fixflow:assignPolicyType id="potentialOwner"/>
<fixflow:skipStrategy/>
</bpmn2:extensionElements>
</bpmn2:userTask>
"extensionElements" 元素内就用来存放各个厂商自己扩展的元素,"fixflow:"开头的 attribute 就是官网元素本身的属性扩展,
官方也是清楚的,他们给的那点肯定是不够用的,所以就有了上面的扩展,3.0出来了肯定会提供更多支持。
3.扩展 BPMN2.0 EMF模型的思路
Fixflow在读写BPMN2.0模型的时候使用了Eclipse官方提供的EMF模型,扩展元素的最好的方式就是不修改原始Eclipse提供的模型,
采用外部注入的方式修改给EMF模型添加新的元素。我们需要重新建立一个EMF模型来放置Fixflow引擎自己扩展的元素定义,
通过EMF提供的注入方法添加到元素的模型保存中去,下面我们一步步来完成这个过程。
4.创建一个EMF模型
这里我们不再详细介绍创建模型文件的过程,不清楚的请参考第三章创建模型。
下面的截图是 fixflow 的扩展元素模型:
这个扩展模型有些需要注意的地方,模型 整体的 Ns Prefix 和 Ns URI 这个两个属性决定了你扩展元素的名称和命名空间。
Attributes 的设置需要注意的事项。
EReference 引用设置需要主要的地方。
创建完毕生成三个模型文件,并生成对应java代码。
5.读写扩展元素
下面的代码就是在web环境下读写BPMN2.0模型扩展元素的代码:
模型文件下载地址: SampleProcess.bpmn.7z
import java.util.List; import org.eclipse.bpmn2.BaseElement;
import org.eclipse.bpmn2.Bpmn2Factory;
import org.eclipse.bpmn2.Bpmn2Package;
import org.eclipse.bpmn2.Definitions;
import org.eclipse.bpmn2.ExtensionAttributeValue;
import org.eclipse.bpmn2.RootElement;
import org.eclipse.bpmn2.di.BpmnDiPackage;
import org.eclipse.bpmn2.util.Bpmn2ResourceFactoryImpl;
import org.eclipse.dd.dc.DcPackage;
import org.eclipse.dd.di.DiPackage;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl.SimpleFeatureMapEntry;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.FeatureMap; import com.founder.fix.bpmn2extensions.fixflow.ConnectorInstance;
import com.founder.fix.bpmn2extensions.fixflow.FixFlowFactory;
import com.founder.fix.bpmn2extensions.fixflow.FixFlowPackage; public class test { public static void main(String[] args) {
//创建资源集
ResourceSet resourceSet = getResourceSet();
//创建资源
Resource resource = resourceSet.createResource(URI.createURI("SampleProcess.bpmn")); try {
//加载资源
resource.load(null);
} catch (Exception e) {
e.printStackTrace();
}
//获取根元素
Definitions definitions = (Definitions) resource.getContents().get(0).eContents().get(0);
//获取process对象
org.eclipse.bpmn2.Process process=null;
for (RootElement rootElement : definitions.getRootElements()) {
if (rootElement instanceof org.eclipse.bpmn2.Process) {
process = (org.eclipse.bpmn2.Process) rootElement;
}
} if(process==null){
return;
} //设置扩展 EAttribute fixflow:dbid
process.eSet(FixFlowPackage.Literals.DOCUMENT_ROOT__DBID, "SampleProcess_1");
//读取扩展 EAttribute fixflow:dbid
process.eGet(FixFlowPackage.Literals.DOCUMENT_ROOT__DBID); ConnectorInstance connectorInstance=FixFlowFactory.eINSTANCE.createConnectorInstance();
//添加扩展元素
addExtensionElement(process,FixFlowPackage.Literals.DOCUMENT_ROOT__CONNECTOR_INSTANCE,connectorInstance);
//读取扩展元素
getExtensionElementList(ConnectorInstance.class,process,FixFlowPackage.Literals.DOCUMENT_ROOT__CONNECTOR_INSTANCE); } /**
* 创建资源集
* @return
*/
private static ResourceSet getResourceSet() { //以下的方式是脱离Eclipse环境在web下使用EMF的时候使用的方式,Eclipse里使用要简单的多。 ResourceSet resourceSet = new ResourceSetImpl();
(EPackage.Registry.INSTANCE).put("http://www.omg.org/spec/BPMN/20100524/MODEL", Bpmn2Package.eINSTANCE);
//注意这里的注册没有这个注册是没有办法通过直接获取扩展元素的
(EPackage.Registry.INSTANCE).put("http://www.founderfix.com/fixflow", FixFlowPackage.eINSTANCE);
(EPackage.Registry.INSTANCE).put("http://www.omg.org/spec/DD/20100524/DI", DiPackage.eINSTANCE);
(EPackage.Registry.INSTANCE).put("http://www.omg.org/spec/DD/20100524/DC", DcPackage.eINSTANCE);
(EPackage.Registry.INSTANCE).put("http://www.omg.org/spec/BPMN/20100524/DI", BpmnDiPackage.eINSTANCE);
FixFlowPackage.eINSTANCE.eClass();
FixFlowPackage xxxPackage = FixFlowPackage.eINSTANCE;
EPackage.Registry.INSTANCE.put(xxxPackage.getNsURI(), xxxPackage);
Bpmn2ResourceFactoryImpl ddd = new Bpmn2ResourceFactoryImpl();
//注意这里的注册没有这个注册是没有办法通过直接获取扩展元素的
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("fixflow", ddd);
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("bpmn", ddd);
resourceSet.getPackageRegistry().put(xxxPackage.getNsURI(), xxxPackage);
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("bpmn", ddd);
return resourceSet;
} /**
* 读取扩展元素 Element
* @param t 扩展元素的java类型
* @param baseElement 主元素
* @param eReference 引用
* @return
*/
@SuppressWarnings("unchecked")
public static <T> List<T> getExtensionElementList( Class<T> t ,BaseElement baseElement,EReference eReference){ //BPMN2.0官方定义每个BaseElement元素都含有扩展元素ExtensionValues
if (baseElement.getExtensionValues().size() > 0) {
for (ExtensionAttributeValue extensionAttributeValue : baseElement.getExtensionValues()) {
FeatureMap extensionElements = extensionAttributeValue.getValue();
Object objectElement = extensionElements.get(eReference, true);
if (objectElement != null) { List<T> tObjList = (List<T>) objectElement;
return tObjList; }
}
} return (List<T>)null;
} /**
* 添加扩展元素
* @param baseElement 主元素
* @param eReference 引用
* @param o 扩展元素对象
* @return
*/
public static boolean addExtensionElement(BaseElement baseElement,EReference eReference,Object o){
final FeatureMap.Entry extensionElementEntry = new SimpleFeatureMapEntry((org.eclipse.emf.ecore.EStructuralFeature.Internal) eReference, o);
if(baseElement.getExtensionValues().size() > 0){
baseElement.getExtensionValues().get(0).getValue().add(extensionElementEntry);
}else{
ExtensionAttributeValue extensionElement = Bpmn2Factory.eINSTANCE.createExtensionAttributeValue();
extensionElement.getValue().add(extensionElementEntry);
baseElement.getExtensionValues().add(extensionElement);
}
return false;
} }