擴充Apache ODE的XPath function

BPEL是XML-base的協定,因此使用了大量的XML技術,包括XPath和XSLT。根據目前最新的BPEL 2.0協定,這兩項只支援到1.0,有點不足,因為BPEL是發佈於2007年,XPath和XSLT 2.0要到2010年才發佈,但好險ODE將XPath實作到2.0,而ODE所使用的XSLT processor - Saxon(9.1.0.8)也有支援XSLT 2.0。ODE自己本身也提供一些XPath的擴充function,但只依靠在XPath 2.0的實作上。

基本上,XPath內建的function多少還是有些不足的,而ODE有提供擴充XPath function,也應該代表開發者自己也可以自己製作擴充function。但分析結果發現,ODE的架構設計上並沒有考慮到這一塊可做plugins,所以必須修改原始碼。而根據ODE的架構圖,必須處理compiler和runtime兩個部份,花了一些時間分析compiler module並將結果畫成Class diagram和Sequence diagram,好理解ODE如何處理BPEL檔案。

Sequence Diagram

Class Diagram

由Sequence Diagram可知,Compiler Module會將BPEL檔案的所有Activity和相關定義轉換成Data Access Object,並且存成副檔名為cdp的檔案,其實就是將Java物件做序列化(serialize),預設是寫成檔案,但可根據需求變更,因為BpelC提供setOutputStream方法可更改output目標。

知道Compiler Module是怎麼運作後,就可以在BPEL文擋內加一些自己想要的功能。接著還要處理Runtime Module的部份,因為就算Compiler Module認識開發者自行定義的東西,Runtime Module1並不認識,為什麼不認識呢?因為Compiler Module只做分析和驗證,並不真正執行。本文接下來會做個簡易的XPath function來示範,大概就會知道是什麼樣子了。

基本上,Class Diagram和Sequence Diagram主要是幫助理解Compiler Module的架構和運作,實際上要增加自己的XPath function,只需要修改JaxpFunctionResolver這支程式,而Runtime Module也不用接觸到ODE的核心框架 - Jacob

JaxpFunctionResolver在Compiler Module和Runtime Module都有,正如上一段所說的,compile時只需要驗證是否正確,runtime時才要真正執行跑出結果,package full path分別是org.apache.ode.bpel.elang.xpath20.compilerorg.apache.ode.bpel.elang.xpath20.runtime

首先處理Compile Module的部份,JaxpFunctionResolver是實作javax.xml.xpath.XPathFunctionResolver,所以找到resolveFunction方法,這方法裏面就是一連串的if else。建議如果擴充的function有一定的數量,可自定義namespace,以便跟既有的做區別。
if (functionName.getNamespaceURI() == null) {
   
} else if (functionName.getNamespaceURI().equals(Namespaces.WS_BPEL_20_NS)
 || functionName.getNamespaceURI().equals(Namespaces.WSBPEL2_0_FINAL_EXEC)) {
   
} else if (functionName.getNamespaceURI().equals(Namespaces.ODE_EXTENSION_NS)) {
   
} else if (functionName.getNamespaceURI().equals(Namespaces.DEPRECATED_XDT_NS)) {
   
}
接著看if內部,都會回傳一個內部類別實例(inner class instance),所以就依樣畫葫蘆在後面自己增加一個內部類別,需繼承javax.xml.xpath.XPathFunction並且實作evaluate方法。參考上面其他的XPathFunction實作,會發現evaluate方法內都只做傳入參數的檢查,例如傳入參數個數、型態之類的,最後都只return空字串。這就是上面所述,compile時只檢查並不執行。如果發現有錯,可以丟出exception和錯誤訊息,在compile時就會提示錯誤讓使用者做正確的修改。這部份大概就是這樣,因為參考一下其他的class就可以知道怎麼處理。

接下來就是Runtime Module的部份了,也是一樣,重複Compiler Module時做的事情,唯一不同的是要真的實作。但是,之後又發現一個問題,雖然在這裡加入了擴充的XPath function,但只能直接給BPEL的Activity調用,例如在Assign的from to裏面使用expression,並不能在XSLT裡面使用。研究了一下Saxon的使用方法,並沒有提供介面或設置可讓XSLT processor可以參考擴充的XPath function,就連ODE提供的也不行。但是Saxon卻提供了一個方法讓processer在處理XSLT的時候可以呼叫外部程式,詳細可參考官方文件。大致上就是使用一個Saxon特定的namespace,如下所示:










利用Saxon提供的機制,就可以呼叫既有的XPath function。但現在還有個問題,如果每用一個擴充的XPath function,就要加一長串的namespace,還得記清楚package full path,也太麻煩了。所以我就在ODE的util module裏面增加一個可以呼叫現有擴充XPath function的代理程式org.apache.ode.utils.xsl.ExtFunctionCall。使用方法如下:

呼叫function的參數如果是string的話,雙層的單引號無法使用\"或\\",必須使用"或'代替。

Util Module下載:source  jar

留言

熱門文章