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:"開頭的
1 <serviceTask id="javaService" 2 name="Java service invocation" 3 activiti:class="org.activiti.examples.bpmn.servicetask.ToUpperCaseFieldInjected"> 4 <extensionElements> 5 <activiti:field name="text" stringValue="Hello World" /> 6 </extensionElements> 7 </serviceTask>
fixflow引擎的擴展都是以"fixflow:"開頭的
1 <bpmn2:userTask id="UserTask_1" fixflow:taskType="FIXFLOWTASK" name="人工任務"> 2 <bpmn2:extensionElements> 3 <fixflow:assignPolicyType id="potentialOwner"/> 4 <fixflow:skipStrategy/> 5 <fixflow:taskCommand id="HandleCommand_3" name="提交" commandType="submit"/> 8 <fixflow:expectedExecutionTime/> 9 <fixflow:formUri> 10 <fixflow:expression xsi:type="fixflow:Expression" id="Expression_3">DemoServlet?action=startOneTask</fixflow:expression> 11 </fixflow:formUri> 12 </bpmn2:extensionElements> 13 <bpmn2:incoming>SequenceFlow_1</bpmn2:incoming> 14 <bpmn2:outgoing>SequenceFlow_3</bpmn2:outgoing> 15 <bpmn2:potentialOwner id="PotentialOwner_1" fixflow:resourceType="user" fixflow:includeExclusion="INCLUDE"name="所有人"> 16 <bpmn2:resourceAssignmentExpression id="ResourceAssignmentExpression_1"> 17 <bpmn2:formalExpression id="所有人">"fixflow_allusers"</bpmn2:formalExpression> 18 </bpmn2:resourceAssignmentExpression> 19 </bpmn2:potentialOwner> 21 </bpmn2:userTask>
每個引擎的廠商都會對BPMN2.0官方元素做出擴展,這就導致了流程定義雖然可以在不同的流程產品相互顯示,但是想運行起來是不可能的。
2.BPMN2.0官方關於擴展元素的支持
可以看到BPMN2.0官方已經提供了擴展元素的存放位置:
1 <bpmn2:userTask id="UserTask_1" fixflow:taskType="FIXFLOWTASK" name="人工任務"> 2 <bpmn2:extensionElements> 3 <fixflow:assignPolicyType id="potentialOwner"/> 4 <fixflow:skipStrategy/> 12 </bpmn2:extensionElements> 13 </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
1 import java.util.List; 2 3 import org.eclipse.bpmn2.BaseElement; 4 import org.eclipse.bpmn2.Bpmn2Factory; 5 import org.eclipse.bpmn2.Bpmn2Package; 6 import org.eclipse.bpmn2.Definitions; 7 import org.eclipse.bpmn2.ExtensionAttributeValue; 8 import org.eclipse.bpmn2.RootElement; 9 import org.eclipse.bpmn2.di.BpmnDiPackage; 10 import org.eclipse.bpmn2.util.Bpmn2ResourceFactoryImpl; 11 import org.eclipse.dd.dc.DcPackage; 12 import org.eclipse.dd.di.DiPackage; 13 import org.eclipse.emf.common.util.URI; 14 import org.eclipse.emf.ecore.EPackage; 15 import org.eclipse.emf.ecore.EReference; 16 import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl.SimpleFeatureMapEntry; 17 import org.eclipse.emf.ecore.resource.Resource; 18 import org.eclipse.emf.ecore.resource.ResourceSet; 19 import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; 20 import org.eclipse.emf.ecore.util.FeatureMap; 21 22 import com.founder.fix.bpmn2extensions.fixflow.ConnectorInstance; 23 import com.founder.fix.bpmn2extensions.fixflow.FixFlowFactory; 24 import com.founder.fix.bpmn2extensions.fixflow.FixFlowPackage; 25 26 27 public class test { 28 29 public static void main(String[] args) { 30 //創建資源集 31 ResourceSet resourceSet = getResourceSet(); 32 //創建資源 33 Resource resource = resourceSet.createResource(URI.createURI("SampleProcess.bpmn")); 34 35 36 try { 37 //加載資源 38 resource.load(null); 39 } catch (Exception e) { 40 e.printStackTrace(); 41 } 42 //獲取根元素 43 Definitions definitions = (Definitions) resource.getContents().get(0).eContents().get(0); 44 //獲取process對象 45 org.eclipse.bpmn2.Process process=null; 46 for (RootElement rootElement : definitions.getRootElements()) { 47 if (rootElement instanceof org.eclipse.bpmn2.Process) { 48 process = (org.eclipse.bpmn2.Process) rootElement; 49 } 50 } 51 52 if(process==null){ 53 return; 54 } 55 56 //設置擴展 EAttribute fixflow:dbid 57 process.eSet(FixFlowPackage.Literals.DOCUMENT_ROOT__DBID, "SampleProcess_1"); 58 //讀取擴展 EAttribute fixflow:dbid 59 process.eGet(FixFlowPackage.Literals.DOCUMENT_ROOT__DBID); 60 61 62 ConnectorInstance connectorInstance=FixFlowFactory.eINSTANCE.createConnectorInstance(); 63 //添加擴展元素 64 addExtensionElement(process,FixFlowPackage.Literals.DOCUMENT_ROOT__CONNECTOR_INSTANCE,connectorInstance); 65 //讀取擴展元素 66 getExtensionElementList(ConnectorInstance.class,process,FixFlowPackage.Literals.DOCUMENT_ROOT__CONNECTOR_INSTANCE); 67 68 69 } 70 71 /** 72 * 創建資源集 73 * @return 74 */ 75 private static ResourceSet getResourceSet() { 76 77 //以下的方式是脫離Eclipse環境在web下使用EMF的時候使用的方式,Eclipse里使用要簡單的多。 78 79 ResourceSet resourceSet = new ResourceSetImpl(); 80 (EPackage.Registry.INSTANCE).put("http://www.omg.org/spec/BPMN/20100524/MODEL", Bpmn2Package.eINSTANCE); 81 //注意這里的注冊沒有這個注冊是沒有辦法通過直接獲取擴展元素的 82 (EPackage.Registry.INSTANCE).put("http://www.founderfix.com/fixflow", FixFlowPackage.eINSTANCE); 83 (EPackage.Registry.INSTANCE).put("http://www.omg.org/spec/DD/20100524/DI", DiPackage.eINSTANCE); 84 (EPackage.Registry.INSTANCE).put("http://www.omg.org/spec/DD/20100524/DC", DcPackage.eINSTANCE); 85 (EPackage.Registry.INSTANCE).put("http://www.omg.org/spec/BPMN/20100524/DI", BpmnDiPackage.eINSTANCE); 86 FixFlowPackage.eINSTANCE.eClass(); 87 FixFlowPackage xxxPackage = FixFlowPackage.eINSTANCE; 88 EPackage.Registry.INSTANCE.put(xxxPackage.getNsURI(), xxxPackage); 89 Bpmn2ResourceFactoryImpl ddd = new Bpmn2ResourceFactoryImpl(); 90 //注意這里的注冊沒有這個注冊是沒有辦法通過直接獲取擴展元素的 91 Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("fixflow", ddd); 92 resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("bpmn", ddd); 93 resourceSet.getPackageRegistry().put(xxxPackage.getNsURI(), xxxPackage); 94 Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("bpmn", ddd); 95 return resourceSet; 96 } 97 98 /** 99 * 讀取擴展元素 Element 100 * @param t 擴展元素的java類型 101 * @param baseElement 主元素 102 * @param eReference 引用 103 * @return 104 */ 105 @SuppressWarnings("unchecked") 106 public static <T> List<T> getExtensionElementList( Class<T> t ,BaseElement baseElement,EReference eReference){ 107 108 //BPMN2.0官方定義每個BaseElement元素都含有擴展元素ExtensionValues 109 if (baseElement.getExtensionValues().size() > 0) { 110 for (ExtensionAttributeValue extensionAttributeValue : baseElement.getExtensionValues()) { 111 FeatureMap extensionElements = extensionAttributeValue.getValue(); 112 Object objectElement = extensionElements.get(eReference, true); 113 if (objectElement != null) { 114 115 List<T> tObjList = (List<T>) objectElement; 116 return tObjList; 117 118 119 } 120 } 121 } 122 123 124 return (List<T>)null; 125 } 126 127 /** 128 * 添加擴展元素 129 * @param baseElement 主元素 130 * @param eReference 引用 131 * @param o 擴展元素對象 132 * @return 133 */ 134 public static boolean addExtensionElement(BaseElement baseElement,EReference eReference,Object o){ 135 final FeatureMap.Entry extensionElementEntry = new SimpleFeatureMapEntry((org.eclipse.emf.ecore.EStructuralFeature.Internal) eReference, o); 136 if(baseElement.getExtensionValues().size() > 0){ 137 baseElement.getExtensionValues().get(0).getValue().add(extensionElementEntry); 138 }else{ 139 ExtensionAttributeValue extensionElement = Bpmn2Factory.eINSTANCE.createExtensionAttributeValue(); 140 extensionElement.getValue().add(extensionElementEntry); 141 baseElement.getExtensionValues().add(extensionElement); 142 } 143 return false; 144 } 145 146 }