JWFDv0.96開源工做流引擎設計
---XML to 數據庫解析過程說明
注:這篇文章中所使用的「函數」就是指JAVA語言中的方法
做者 comsci 2011.4.25 四川。成都
簡要說明:
實際上,用戶經過JWFD流程設計器設計出的流程圖的結構通常是保存在XML格式的文件中的(XML文件結構請參考」JWFDv0.96 開源工做流引擎設計-流程圖XML結構說明.doc「),而流程引擎的運行和控制倒是創建在對後臺數據庫的基本表結構的SQL操做基礎上面的(數據庫結構 請參考」JWFDv0.96 開源工做流引擎設計-數據庫結構說明.doc「),所以從前端設計器XML到後臺數據庫基本表的數據解析和轉換過程對於整個JWFD工做流系統的設計就顯 得尤其重要,因此我在初步完成了JWFD工做流系統設計文檔的編寫以後,發現這個環節必須補上,所以我將在這篇文檔中,詳細介紹JWFD工做流系統的 XML-數據庫解析過程(包括代碼實現)
我儘可能把整個設計思想和實現代碼的結構都用很通俗的語言來說述清楚,方便你們理解,若是通過本身的思考以後,還有不理解的地方,能夠給我發郵件或 者在JWFD的論壇上面提問題,很是感謝fireflow的非也和openjweb的阿寶同志的大力支持,JWFD也有本身的論壇板塊
http://www.fireflow.org/forum-33-1.html,若是你們對JWFD有什麼意見和建議,能夠再這個論壇上面發帖,包括提交BUG報告
設計與實現方法:
採用基於JGRAPH開源軟件的流程圖數據結構XML模型,經過調用JGraphGXLCodec類的流程圖編碼和解碼方法,將設計器設計出來的流程圖轉 換爲GXL(XML)-文件格式存儲在本地硬盤(服務器)上面(解釋:gxl文件格式就是一種簡單的圖形xml文件存儲格式),而後經過調用 ParserGxl類和GxlToDatabase類實現將XML文件中存儲的流程圖數據轉換到數據庫中進行存儲,以便實現下一步JWFD流程引擎對流程 圖數據的處理。
JWFD 流程圖-數據庫轉換的實現過程
上面的圖例是JWFD開源工做流系統裏面的流程圖XML-數據庫轉換的實現流程,而具體負責實現上述功能的代碼是在JWFD的代碼包裏面的 org.jwfd.workflowDesigner.FLCLs.Gxl 的package裏面的下面三個類,以下
org.jwfd.workflowDesigner.FLCLs.Gxl.GxlToDatabase.java
org.jwfd.workflowDesigner.FLCLs.Gxl.JgraphGxlCodec.java
org.jwfd.workflowDesigner.FLCLs.Gxl.ParserGxl.java
主要的實現方法用簡單的語言來描述就是: 經過調用DOM(一種XML解析工具包)類中的函數對流程圖文件的XML結構進行解析,對存儲在XML文件裏面的流程圖的拓撲結構(節點和鏈接線)進行提 取操做,而後把提取出來的流程圖拓撲結構數據 經過數據庫的SQL操做insert,update等方式插入到已經創建好的MYSQL數據庫的JWFD流程基本表中(JWFD的流程基本表的表結構請參 考 JWFDv0.96 開源工做流引擎設計-數據庫結構說明.doc 一文)
須要說明的是,XML解析模塊在JWFD中主要是依靠JGRAPH開源軟件的XML處理模塊來實現的,JWFD經過調用這個XML處理模塊,而後加上XML數據整理和數據庫操做方法來共同完成這一過程
public ParserGxl(String fe, String gid) throws Exception {}
這個類中的主函數 ParserGxl()是一個DOM類的變形函數,主要用於從流程圖的XML文檔中把流程圖的節點,鏈接線,座標等數據提取出來,若是你們須要改造流程圖的定義XML文件格式,那麼就須要對這個函數中的某些代碼有所瞭解
如今咱們來對具體的實現代碼進行分析
File f = new File(fe); 這句代碼的意義是經過參數fe傳遞過來的文件名稱創建一個文件類型的變量f,這個變量f就是後面DOM類用來讀取xml文件的文件名稱
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
這句代碼的意義是創建一個XML文檔數據處理模型的實例 .newInstance的意思就是在內存中建立一個XML數據模型的實例
DocumentBuilder db = dbf.newDocumentBuilder();
這句代碼的意思是實例化一個XML文檔解析類
Document doc = db.parse(f);
這句代碼的意思是裝載前面導入的XML文件
Element gxl = (Element) doc.getDocumentElement();
NodeList graph_list = gxl.getChildNodes();
這兩句代碼的做用是初始化須要解析的XML文件,並獲取該XML文件的第一個元素,並從第一個元素列表list開始解析這個XML數據
實際上,前面幾句代碼聯合在一塊兒就是一個初始化XML數據處理類的代碼段,這些代碼段是統一在一塊兒的,不可以分開使用,這點須要注意,特別是你們在複製這段代碼的時候要注意
它們是一個總體,做用是初始化一個XML數據模型實例,併爲下面的提取XML數據元作準備
if (graph_list.getLength() == 0) { return;}
這段代碼的意思經過判斷xml數據列表的長度是否爲0,並執行返回命令
for (int graph_index = 0; graph_index < graph_list.getLength(); graph_index++) {
for循環,循環控制變量graph_index是XML文件的數據段長度,從這個循環開始程序開始自動的提取xml文件的數據
Node graph_node = graph_list.item(graph_index);
定義一個Node類型變量 並從graph_list數組item中提取graph_node元數據
if (graph_node.getNodeName().equals("graph")){}
這個IF判斷的用處是經過判斷xml數據段的初始名稱是否爲"graph",若是是則決定執行下面的操做,getNodeName()方法是用來程序讀取XML數據段節點名稱的操做
Element graph_elem = (Element) graph_node;
定義一個Element元素變量,並將graph_node變量類型強行轉化爲Element類型
NodeList list = graph_elem.getChildNodes();
定義一個NodeList變量list 並將前面定義的graph_elem裏面的子元素提取出來
for (int i = 0; i < list.getLength(); i++) {}
這個FOR循環把前面得到xml流程圖的LIST數據列表的長度做爲循環控制條件,循環體內部是讀取XML流程節點和鏈接線數據的操做函數,讀取這些數據並同步寫入數據庫的表中
注意,這個for循環和前面另一個for循環共同發揮做用,一塊兒來作這個XML數據提取工做,由於XML數據結構是嵌套的,所以須要兩個FOR循環來一塊兒使用
=================================================================
if (node.getAttributes() != null && node.getNodeName() != null) {
String type = node.getNodeName().toString().toLowerCase();
if (type.equals("node")) {
Node edgeid = node.getAttributes().getNamedItem("id");
String id = edgeid.getNodeValue();
這兩個嵌套的if判斷語句是用來過濾須要提取的XML數據的標誌頭的,第一個if判斷語句是過濾空數據的操做,就是屬性和名稱都爲空null的數據就不進 入下一步的提取操做,而非空的數據則須要進行tostring()-字符串轉換操做並轉化爲小寫lowerCase()
第二個if語句是判斷type數據名稱是否爲node-節點 若是數據段標誌爲node,則咱們就能夠對這個XML數據段中包含的數據進行提取,這裏主要提取兩個標誌中的數據,一個是節點的id,一個是鏈接邊 edge的id,並在下面的wis.into_node()方法中把這兩個關鍵id值寫入到數據庫的表結構中去
=================================================================
wis.into_node(getLabel(node),id,gid,getcondition(node));
這句代碼是這個類中全部代碼的一個核心語句,意義就是把提取出來的XML文件中的流程圖節點的id和節點包含的條件控制參數數據一塊兒寫入數據庫中,固然這個方法是引用另一個類GxlToDatabase中的操做,該操做其實是一個SQL操做,具體的代碼以下
"insert into step_main(step_name,graph_id,step_id,cond) values ('" +step_name +"','" + gid + "','" + step_id + "','" + condition + "')"
Insert語句中使用的數據庫表名稱 step_main是JWFD數據結構的節點主表,其表結構的詳細說明請參考文檔 JWFDv0.96 開源工做流引擎設計-數據庫結構說明.doc
這個語句中的insert插入操做僅僅涉及step_main表中的step_name(節點名稱)字段,graph_id(流程圖id)字 段,step_id(節點id)字段,cond(節點嵌入條件控制參數)字段,而這些字段中的具體數據就是用前面所描述的那些JAVA語句從XML數據文 件中提取出來的,因此按照insert操做的順序咱們能夠了解 getLabel(node)是取節點名稱的操做,id是流程節點的id,gid是流程圖的id,getcondition(node)是取節點嵌入的條 件控制參數的操做,這樣的說明是否讓你們對本語句所執行的操做和涉及到數據結構有比較清晰的理解了呢? 若是還有不清楚地地方,請給我發郵件或者在論壇上面發帖或者加個人QQ(784092877),我會盡可能回答你們的問題
接下來的這個IF判斷語句是繼續前面的工做,不過此次是提取XML中的節點之間的鏈接線edge的數據,若是類型爲edge 則進行下面的提取操做
if (type.equals("edge"))
=================================================================
String from = null;
String to = null;
String edge = null;
String prop = null;
Node edgeid = node.getAttributes().getNamedItem("id");
Node tmp = node.getAttributes().getNamedItem("from");
Node tmp1 = node.getAttributes().getNamedItem("to");
edge = edgeid.getNodeValue();
from = tmp.getNodeValue();
to = tmp1.getNodeValue();
這段代碼完成幾個工做,前面四行定義四個字符串(from,to,edge,prop)變量,用於存儲接下來要提取的XML文件中的鏈接線數據, 其中from用於存儲節點鏈接線的起始端點,to變量用於存儲節點鏈接線的終止端點,兩個節點之間的鏈接線就是經過起始端點和終止端點來定義的,另外加上 一個Edgeid變量,這個變量做爲鏈接邊的惟一標誌id
而接下來的代碼段中的粗體字所表示的代碼就是本程序用於提取xml文檔中的數據的操做函數,這些操做代碼來源於JAVA的XML處理模塊dom類,你們能夠找找專門介紹DOM數據處理的文章來看看,我在這裏就不作詳細介紹了
本段最後的三行代碼就是利用getNodeValue()函數把XML數據段中的流程圖的邊,邊起始點,邊終止點的具體數據提取出來,並存放在前面定義的字符串變量edge,from,to中,以便下一步的處理
=================================================================
try {
wis.into_edge(edge, from, to, gid, getcondition(node));
}catch (Exception ex) {
System.out.println("建立edge異常:" +ex);
}
在理解前面一段的代碼的意義以後,咱們再來看看這段代碼,這是一個try-catch異常處理語句包圍的功能執行語句,前面咱們已經介紹過這種 wis類中的一個函數 wis.into_node,而這裏的wis.into_edge的功能和這個wis.into_node的功能是對應的,into_node()函數是 系統在提取了xml數據段中的節點相關數據以後,往數據庫中寫入這些數據的功能代碼函數,而
into_edge()函數倒是系統在提取了XML數據段中的節點鏈接邊的相關數據以後,往數據庫中寫入這些節點鏈接邊數據的功能代碼函數,這個功能函數其實和前面介紹過的into_node()函數同樣,是一個SQL語句,具體代碼以下
"insert into edge_control(edge_id,from_step,to_step,graph_id,prop) values ('" +edgeid + "','" + from +"','" + to + "','" + gid + "','" + prop + "')"
前面介紹過這種相似的SQL操做,這裏就再簡略介紹下
edge_control 是 JWFD流程數據庫結構中的一個基礎表,這個基礎表是系統用於存儲流程圖中鏈接邊edge的一張表,其詳細的數據結構請參考 JWFDv0.96 開源工做流引擎設計-數據庫結構說明.doc
向edge_control數據表中寫入的數據參數分別以下
Edge_id 兩個節點間鏈接線段的惟一標識id
From_step 鏈接線段的起始節點id
To_step 鏈接線段的終止節點id
Graph_id 該鏈接線段所在的流程圖的id
Prop 該鏈接線所包含的嵌入式參數(未使用),這裏經過getcondition(node)函數來得到這個參數,實際上並未使用,這個參數是節點的嵌入數據,而不是鏈接邊的嵌入數據
全部這些參數都已經經過前面的XML數據提取操做保存在本類定義的字符串變量中了,這個sql操做就用這些字符串變量做爲寫入數據庫中的實際數據變量
=================================================================
到這裏爲止,系統提取XML數據的功能代碼 和寫入數據庫的操做代碼 就基本介紹完了,這個類的剩下的函數的代碼 都是同一結構的函數,其主要功能是提取xml數據段中的詳細參數,好比說getlabel是提取xml數據段中的節點的名稱,注意是名稱而不是id,而 getcondition是提取節點中嵌入的條件表達式參數,getBound是提取節點在整個流程圖的二維座標的數據,這些功能代碼的結構均來自 jgraph的一個子項目 jgraphpad的代碼包中,我僅僅是作了下修改,具體的代碼結構我就不作詳細的介紹了
protected String getcondition(Node node){}
protected String getLabel(Node node) {}
protected Vector getBound(Node node) {}
只有一個地方須要注意下,若是你們要自定義這些函數,好比說根據系統的須要修改了XML文件的自定義的變量,如今須要提取這些新的定義變量,僅僅須要修改這些函數的一行,就能夠實現代碼複用
if (attr.getNodeName().equals("attr")
&& attr
.getAttributes()
.getNamedItem("name")
.getNodeValue()
.equals(
"Condition"))
若是你們須要複用這段代碼,只須要修改這段代碼的最後一行的參數 這裏是Condition,而僅僅須要把這個condition修改成你定義的XML的參數便可,而整個函數均可以當即複用,並不須要修改其餘的部分,固然須要修改下函數的名稱
=================================================================
實際上,到目前爲止,經過這裏所介紹的代碼,咱們就完成了將經過流程設計器設計好的流程圖的XML文件轉換並保存在後臺的數據庫中這一過程了,在 實現這一個過程以後,咱們就能夠經過對數據庫中的這些流程圖數據進行SQL操做,來實現一個流程引擎的一系列功能了,流程引擎的底層操做API的結構和說 明請參考下面的文檔和代碼
JWFDv0.96 開源工做流系統-二次開發API簡易說明.doc
JWFDv0.96 開源工做流引擎設計-流程圖XML結構說明.doc
JWFDv0.96 開源工做流引擎設計-自動運行控制器結構說明.doc
上面所說起的文檔,我均壓縮並上傳 下載地址爲php
http://www.cnblogs.com/comsci/favorite/260690.htmlhtml