簡介:了解 BIRT 擴展點模型,使用新的 V2.3+ 擴展模型在 BIRT 中創建基 本聚合擴展。
本文介紹商業智能和報告工具(Business Intelligence and Reporting Tools,BIRT)擴展點模型,並在 BIRT V2.3.x 和 V2.5.x 中實際創建一個聚合 擴展。在較早的 BIRT 版本中,創建聚合擴展的方式是擴展 org.eclipse.birt.data.aggregation 擴展點,這會在一個名為 Total 的全局對 象中添加一個小函數,您可以在整個報告的任何表達式中使用該函數,其工作原 理類似於腳本函數擴展點。
但是,從 BIRT V2.2 到 V2.3,聚合擴展已經發生了變化。新的方式更加復雜 ,但可以在 Aggregation Widgets 下拉列表中得到一個不錯的聚合,還為參數和 表達式提供了漂亮的文本框。當創建此擴展時,可以在您的表中以列綁定的形式 訪問結果。
從總體上看,新的聚合擴展點包含一個對象,該對象是 IAggregationFactory 接口的擴展。可以在此接口中重載方法來完成 3 項操作:
初始化您的工廠(在構造函數中)
提供由工廠提供的一組聚合(以列表形式提供,包含聚合對象的實際實例)
返回聚合對象的單一實例
聚合的每個實例都需要實現 IAggrFunction 接口。需要實現許多含義明顯的 方法,比如 getName、getDataType 和 getParmaeterDefn,還需要實現其他含義 不太明顯的方法。例如,getNumberOfPasses() 和 getType() 方法是相關的。 getType() 方法制定此聚合器的執行方式和類型。有兩種聚合類型: SUMMARY_AGGR 表示只為摘要計算該聚合(比如表的表頭或表尾),RUNNING_AGGR 表示為表中的每一行或表尾計算聚合。getNumberOfPasses() 方法顯示獲得結果 所需的 pass 數。所有基於評級的聚合器,比如 TopNpercent、PercentSum 和 Percentile,都會返回值 2,其余聚合器返回值 1。
IAggrFunction 接口的實際實現必須返回其 newAccumulator() 方法中的 Accumulator 類的一個擴展。Accumulator 負責執行實際的計算。有一些默認方 法需要重載,最重要的是 onRow(),表中的每一行都需要調用該方法。使用此方 法,您可以解析函數的參數並執行計算。對於 SUM,可以添加到某個已存儲的數 字;對於 ave,既可以保存到某個列表中進行存儲,也可以添加到一個累計總計 並跟蹤調用次數。無論您如何執行計算,實際計算都需要在這裡完成。getValue () 獲取您的計算的最終值或當前值。所以,對於 SUM 操作,您將會返回總數/計 數操作。在正在運行的聚合器中,將只返回正在計算的值。
下一節的示例將展示如何創建一個簡單的 Word Count 聚合器。此聚合獲取一 列中的所有句子並計算字數,返回一個包含該列的字數的整數值。對這種聚合的 需求很少,所以還不存在這樣的聚合。對於本文中的練習,建議使用 Eclipse BIRT All-in-One 分發版。
創建新聚合插件
要創建新聚合插件:
單擊 File > New > Other 創建一個新插件項目。展開 Plug-In Development 文件夾,然後單 擊 Plug-in Project。
在 New Plug-in Project 窗口中(如圖 1 所示) ,在 ID 字段中為項目提供一個惟一名稱,使用合適的信息完成 Version、Name 和 Provider 字段。
圖 1. 項目屬性
指定 Java™ 2 Platform, Standard Edition (J2SE) V1.5 作為執行環境,以保持與 BIRT 基本 兼容。
在 Options 區域,清除 This plug-in will make contributions to the UI 復選框。通過清除此復選框,可以限制可用模板的數量。我們不打算為此項目使 用模板。
在 Rich Client Application 區域,選擇 No,因為這不是一個 Eclipse 富客戶端項目。單擊 Next。
在 Templates 頁面上,清除 Create a plug-in using one of the templates 復選框,然後單擊 Finish。如 果現在還未處於 Plug-In 開發透視圖中,系統將提示您打開它。
設置擴展點
創建好新項目之後,就可以設置擴展點了。為此,執行以下操作:
在打開的清單窗口中,單擊 Extensions 選項卡,然後單擊 Add。
在 Extension Point Selection 窗口中(如圖 2 所示),清除 Show only extension points from the required plug-ins 復選框。
圖 2. 創建新擴展
在 Extension Point filter 字段中,鍵入 org.eclipse.birt.data。將會出 現聚合擴展點。當添加此擴展點時,系統將提示您添加依賴關系。
創建必要的聚合類
現在您已經添加了聚合擴展點,接下來需要添加一個新 AggregationFactory 。為此,右鍵單擊剛才添加的聚合擴展點,指向 New,然後單擊 AggregationFactory,如圖 3 所示。注意,您並未添加聚合,聚合是以前的擴展 方法,這種方法現在已被淘汰。AggregationFactory 是此插件的主要入口點,負 責注冊可用的聚合類型,並在運行時創建這些聚合的實例。
圖 3. 創建新 AggregationFactory
添加了工廠的定義之後,您將獲得一個文本項,其中包含工廠的完全限定包和 類名。從圖 4 可以看到,該工廠名為 com.digiassn.blogspot.birt.aggregators.wordcount.WordCountFactory。請記 住,此工廠可以注冊和創建多個聚合類型,但這需要在代碼體中操作。在 Extension Element Details 區域,鍵入或浏覽到工廠類的名稱,然後單擊文本 框旁邊的 class 超鏈接。
圖 4. 創建新工廠類
New Java Class 向導已經擁有了合適的包和類信息。確認 Java Class 頁面 上的設置(如圖 5 所示),然後單擊 Finish。
圖 5. 工廠類屬性
打開類的源代碼,如圖 6 所示。如果無法找到 org.eclipse.birt.* imports ,請返回並保存清單窗口中的更改。請記住,您需要為類添加必要的繼承抽象方 法。
圖 6. 工廠類框架
您的類包含 3 個函數:一個構造函數、一個 getAggregations() 方法(返回 一個 IAggrFunction),以及一個 getAggregations() 方法(返回一個列表)。 getAggregations() 方法向調用者返回一個 IAggrFunction 類型列表,使調用者 知道此工廠可以生成的各個聚合的類型。調用者負責在列表上進行迭代,並調用 IAggrFunctions 方法來獲得描述。對於我們創建的工廠,我們不關心這些描述, 工廠將負責返回和維護此列表。
向 getAggregation() 方法傳入聚合的名稱。該方法獲取一個名稱並提供一個 IAggrFunction 結果,清單 1 顯示了示例工廠。
清單 1. 完成之後的工廠類
public class WordCountFactory implements IAggregationFactory {
HashMap<String, IAggrFunction> aggregateMap;
public WordCountFactory() {
aggregateMap = new HashMap<String, IAggrFunction> ();
BasicWordcount wordCountAggregation = new BasicWordcount ();
aggregateMap.put(wordCountAggregation.getName(), wordCountAggregation);
}
public IAggrFunction getAggregation(String aggregationName) {
return aggregateMap.get(aggregationName);
}
public List getAggregations() {
return new ArrayList<IAggrFunction>(aggregateMap.values ());
}
}
創建單獨的聚合描述類
接下來,在 src 文件夾中創建一個新包,將其命名為 com.digiassn.blogspot.birt.aggregators.implIn。在這個新包之下,創建一個 類 BasicWordCount。在 Java Class 窗口中,選擇 Inherited abstract methods 復選框,以便此類可以繼承 org.eclipse.birt.data.engine.api.aggregation.IAggrFunction 接口,如圖 7 所示。
圖 7. 創建新 IAggrFunction 實現
IAggrFunction 類具有兩項任務:它將自身描述為工廠可以創建的聚合,它還 會創建 Accumulator 類的實例來為您的聚合執行實際工作。清單 2 給出了代碼 。
清單 2. 完成後的聚合函數和 Accumulator 類
public class BasicWordcount implements IAggrFunction {
private final static String sDescription =
"This aggregation will count all words in a column and return the count.";
private final static String sName = "Word Count";
private final static String sDisplayName = "Basic Word Count Aggregator";
public int getDataType() {
return DataType.INTEGER_TYPE;
}
public Object getDefaultValue() {
return new Integer(0);
}
public String getDescription() {
return this.sDescription;
}
public String getDisplayName() {
return this.sDisplayName;
}
public String getName() {
return this.sName;
}
public int getNumberOfPasses() {
return 1;
}
public IParameterDefn[] getParameterDefn() {
IParameterDefn paramDef = new IParameterDefn() {
public boolean supportDataType(int paramType) {
if (paramType == DataType.STRING_TYPE)
{
return true;
}
return false;
}
public boolean isOptional() {
return false;
}
public boolean isDataField() {
return false;
}
public String getName() {
return "StringColumn";
}
public String getDisplayName() {
return "String Column";
}
public String getDescription() {
return "A column expression that is a String";
}
};
IParameterDefn[] parameterDefinitionArray = new IParameterDefn[]
{paramDef};
return parameterDefinitionArray;
}
public int getType() {
return IAggrFunction.SUMMARY_AGGR;
}
public boolean isDataOrderSensitive() {
return false;
}
public Accumulator newAccumulator() {
return new Accumulator()
{
int sum;
@Override
public Object getValue() throws DataException {
return new Integer(sum);
}
@Override
public void onRow(Object[] incomingStrings) throws DataException {
String localString = (String) incomingStrings [0];
sum += localString.split(" ").length;
}
};
}
}
此類中的大部分方法只是簡單描述要在 BIRT Aggregation Widgets 下拉列表 中顯示的聚合的各個方面,比如數據類型、標題和描述信息。這 3 個方面有必要 進一步解釋一下。首先是 getParameterDefn() 方法,它返回一個 IParameterDefn 對象數組,可以在該數組中定義聚合需要的參數。一個聚合可以 有多個參數,這就是為什麼要以數組的形式返回參數。此方法向 BIRT 引擎簡單 描述這些參數及其類型。在本例中,僅有一個參數(列表達式),它將是一個字 符串。
那麼,如果參數在 getParameterDefn() 方法中進行描述,要將它們傳入到何 處來執行實際工作呢?IAggrFunction 對象還充當著 Accumulator 類的工廠,該 對象應該在 newAccumulator 方法中創建。Accumulator 是在聚合中執行實際工 作的類。它有兩個方法需要重載:getValue() 和 onRow()。對於在 BIRT 中處理 的每一行,如果使用此聚合,數據綁定將調用 onRow()。作為一個參數,onRow 接收一個包含聚合參數的數組,這些參數由 getParameterDefn() 描述。在更加 健壯的方案中,可以調用 getParameterDefn() 並測試傳入 onRow() 的參數是否 與定義匹配。但是,本文中的簡單示例跳過了這一步。onRow() 方法還負責執行 處理工作。在上面的聚合代碼示例中,它僅用於增加正在計算的字符串總字數。 當報告准備好顯示值時,它調用 getValue() 方法。
需要進一步說明的另一個元素是 IAggrFunctions getType() 方法。兩種聚合 類型(SUMMARY_AGGR 和 RUNNING_AGGR)定義該方法屬於哪種聚合類型;它出現 在報告表的表頭或表尾,還是顯示在每一行中;它在計算時顯示的是累計總計, 還是平均值。
測試插件
可以輕松測試此插件,無需象測試任何 Eclipse 插件一樣進行部署:只需啟 動另一個 Eclipse 實例即可。啟動另一個實例的最簡單方式是從 plugin.xml/manifest 窗口的 Overview 選項卡上啟動。在此選項卡上,在 Testing 區域,單擊 Launch an Eclipse application 鏈接,如圖 8 所示。
圖 8. 測試插件
圖 9 顯示了一個簡單報告,可以根據該報告來測試插件。將一個聚合組件插 入到此報告的表尾。
圖 9. 向報告添加聚合
在 Aggregation Widgets 下拉列表中,選擇 Basic Word Count 聚合器並輸 入列表達式,以指向包含想要統計的句子的列,如圖 10 所示。
圖 10. Aggregation Builder
運行報告並驗證結果。圖 11 顯示了生成的報告。
圖 11. 報告結果
結束語
借助本文中的示例,您現在很好地了解了 BIRT 擴展點框架。現在您可以自行 構建一些聚合來在報告中使用,本文還展示了 BIRT 延伸到其開箱即用功能之外 的能力。請確保您使用了 plugin.xml/manifest 窗口的 Export Wizard 向導來 導出插件,並將該插件復制到您的 BIRT 目標環境(可以是 Web 應用程序或其他 BIRT 設計器環境)的 Plugins 文件夾內。否則,您部署的報告將無法運行,而 且編輯您報告的任何人都需要刪除聚合定義。