第十四章 高级特性-海纳百川:BIRT报表扩展点

如果仅仅只是前面章节提到的BIRT的设计器的便捷性和BIRT引擎提供的用户自定义BIRT报表展示器等自定义特性,只是表现在BIRT报表作为工具的优势,或者作为服务提供者为系统集成做出的贡献,但这还不足以让BIRT成为eclipse开源社区排名前六的基础插件平台。

众所周知,大凡伟大的IT作品,皆是以开放为基础。ios的app store,android的app market,eclipse的plug-in,maven的osgi,microsoft的windows虽然闭源,但提供了visual studio应用开发平台,而visual studio是一个很优秀的平台;

BIRT同样也提供了扩展点,为它的数据源,数据集,数据操作函数,数据展示,数据导出,图表等等提供多数据源,多种形式的展示,多种格式的导出等等扩展。比如Oracle给multimedia CLOB提供的新特性,只要实现BIRT的数据源,数据集和数据展示,数据导出的新特性,同样可以用BIRT报表进行展示;任何第三方,无论是数据库厂商,还是数据提供商,例如医院,教育机构,航天航空机构等等,都可以实现这些扩展点中提供的接口和实现类,来完成报表的功能。

下面先从一个最简单的扩展例子——扩展BIRT报表的聚合函数,开始着手详细讲解BIRT的扩展点。感谢IBM开源社区提供这个古老的案例。

本节介绍商业智能和报告工具(Business Intelligence and Reporting ToolsBIRT)扩展点模型,并在 BIRT V2.3.x 和 V2.5.x 中实际创建一个聚合扩展。在较早的 BIRT 版本中,创建聚合扩展的方式是扩展 org.eclipse.birt.data.aggregation 扩展点,这会在一个名为 Total 的全局对象中添加一个小函数,您可以在整个报告的任何表达式中使用该函数,其工作原理类似于脚本函数扩展点。

但是,从 BIRT V2.2 到 V2.3,聚合扩展已经发生了变化。新的方式更加复杂,但可以在 Aggregation Widgets 下拉列表中得到一个不错的聚合,还为参数和表达式提供了漂亮的文本框。当创建此扩展时,可以在您的表中以列绑定的形式访问结果。

从总体上看,新的聚合扩展点包含一个对象,该对象是 IAggregationFactory 接口的扩展。可以在此接口中重载方法来完成 3 项操作:

· 初始化您的工厂(在构造函数中)

· 提供由工厂提供的一组聚合(以列表形式提供,包含聚合对象的实际实例)

· 返回聚合对象的单一实例

聚合的每个实例都需要实现 IAggrFunction 接口。需要实现许多含义明显的方法,比如 getNamegetDataType 和getParmaeterDefn,还需要实现其他含义不太明显的方法。例如,getNumberOfPasses() 和 getType() 方法是相关的。getType() 方法制定此聚合器的执行方式和类型。有两种聚合类型:SUMMARY_AGGR 表示只为摘要计算该聚合(比如表的表头或表尾),RUNNING_AGGR 表示为表中的每一行或表尾计算聚合。getNumberOfPasses() 方法显示获得结果所需的 pass 数。所有基于评级的聚合器,比如 TopNpercentPercentSum 和 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 字段中为项目提供一个惟一名称,使用合适的信息完成VersionName 和 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. 创建新扩展


1 在 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. 完成之后的工厂类

[java]  view plain copy
  1. public class WordCountFactory implements IAggregationFactory {  
  2.     HashMap<String, IAggrFunction> aggregateMap;  
  3.       
  4.     public WordCountFactory() {  
  5.         aggregateMap = new HashMap<String, IAggrFunction>();  
  6.           
  7.         BasicWordcount wordCountAggregation = new BasicWordcount();  
  8.           
  9.         aggregateMap.put(wordCountAggregation.getName(), wordCountAggregation);  
  10.     }  
  11.   
  12.     public IAggrFunction getAggregation(String aggregationName) {  
  13.           
  14.         return aggregateMap.get(aggregationName);  
  15.     }  
  16.   
  17.     public List getAggregations() {  
  18.           
  19.         return new ArrayList<IAggrFunction>(aggregateMap.values());  
  20.     }  
  21.   
  22. }  

创建单独的聚合描述类

接下来,在 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 类

[java]  view plain copy
  1. public class BasicWordcount implements IAggrFunction {  
  2.       
  3.     private final static String sDescription =   
  4.         "This aggregation will count all words in a column and return the count.";  
  5.     private final static String sName = "Word Count";  
  6.     private final static String sDisplayName = "Basic Word Count Aggregator";  
  7.       
  8.     public int getDataType() {  
  9.         return DataType.INTEGER_TYPE;  
  10.     }  
  11.   
  12.     public Object getDefaultValue() {  
  13.         return new Integer(0);  
  14.     }  
  15.   
  16.     public String getDescription() {  
  17.         return this.sDescription;  
  18.     }  
  19.   
  20.     public String getDisplayName() {  
  21.         return this.sDisplayName;  
  22.     }  
  23.   
  24.     public String getName() {  
  25.         return this.sName;  
  26.     }  
  27.   
  28.     public int getNumberOfPasses() {  
  29.         return 1;  
  30.     }  
  31.   
  32.     public IParameterDefn[] getParameterDefn() {  
  33.         IParameterDefn paramDef = new IParameterDefn() {  
  34.             public boolean supportDataType(int paramType) {  
  35.                 if (paramType == DataType.STRING_TYPE)  
  36.                 {  
  37.                     return true;  
  38.                 }  
  39.                   
  40.                 return false;  
  41.             }  
  42.               
  43.             public boolean isOptional() {  
  44.                 return false;  
  45.             }  
  46.               
  47.             public boolean isDataField() {  
  48.                 return false;  
  49.             }  
  50.               
  51.             public String getName() {  
  52.                 return "StringColumn";  
  53.             }  
  54.               
  55.             public String getDisplayName() {  
  56.                 return "String Column";  
  57.             }  
  58.               
  59.             public String getDescription() {  
  60.                 return "A column expression that is a String";  
  61.             }  
  62.         };  
  63.           
  64.         IParameterDefn[] parameterDefinitionArray = new IParameterDefn[]   
  65.                                 {paramDef};  
  66.         return parameterDefinitionArray;  
  67.     }  
  68.   
  69.     public int getType() {  
  70.         return IAggrFunction.SUMMARY_AGGR;  
  71.     }  
  72.   
  73.     public boolean isDataOrderSensitive() {  
  74.         return false;  
  75.     }  
  76.   
  77.     public Accumulator newAccumulator() {  
  78.         return new Accumulator()  
  79.         {  
  80.             int sum;  
  81.       
  82.             @Override  
  83.             public Object getValue() throws DataException {  
  84.                 return new Integer(sum);  
  85.             }  
  86.   
  87.             @Override  
  88.             public void onRow(Object[] incomingStrings) throws DataException {  
  89.                 String localString = (String) incomingStrings[0];  
  90.                   
  91.                 sum += localString.split(" ").length;  
  92.             }  
  93.               
  94.         };  
  95.     }  
  96. }  

此类中的大部分方法只是简单描述要在 BIRT Aggregation Widgets 下拉列表中显示的聚合的各个方面,比如数据类型、标题和描述信息。这 个方面有必要进一步解释一下。首先是 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-ODA数据源扩展,XML emitter扩展,chat扩展等等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值