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

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

第十四章 高级特性-海纳百川: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 接口的扩展。可以在此接口中重载方法来完成 项操作:

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

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

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

聚合的每个实例都需要实现 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 窗口中(如图 所示),在 ID 字段中为项目提供一个惟一名称,使用合适的信息完成VersionName 和 Provider 字段。 

图 1. 项目属性

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

指定 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 窗口中(如图 所示),清除 Show only extension points from the required plug-ins 复选框。 

图 2. 创建新扩展

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

1 在 Extension Point filter 字段中,键入 org.eclipse.birt.data。将会出现聚合扩展点。当添加此扩展点时,系统将提示您添加依赖关系。

创建必要的聚合类

现在您已经添加了聚合扩展点,接下来需要添加一个新 AggregationFactory。为此,右键单击刚才添加的聚合扩展点,指向 New,然后单击 AggregationFactory,如图 所示。注意,您并未添加聚合,聚合是以前的扩展方法,这种方法现在已被淘汰。AggregationFactory 是此插件的主要入口点,负责注册可用的聚合类型,并在运行时创建这些聚合的实例。


图 3. 创建新 AggregationFactory

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

添加了工厂的定义之后,您将获得一个文本项,其中包含工厂的完全限定包和类名。从图 可以看到,该工厂名为 com.digiassn.blogspot.birt.aggregators.wordcount.WordCountFactory。请记住,此工厂可以注册和创建多个聚合类型,但这需要在代码体中操作。在 Extension Element Details 区域,键入或浏览到工厂类的名称,然后单击文本框旁边的 class 超链接。


图 4. 创建新工厂类

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

New Java Class 向导已经拥有了合适的包和类信息。确认 Java Class 页面上的设置(如图 所示),然后单击 Finish。


图 5. 工厂类属性

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

打开类的源代码,如图 所示。如果无法找到 org.eclipse.birt.* imports,请返回并保存清单窗口中的更改。请记住,您需要为类添加必要的继承抽象方法。


图 6. 工厂类框架

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

您的类包含 个函数:一个构造函数、一个 getAggregations() 方法(返回一个 IAggrFunction),以及一个 getAggregations() 方法(返回一个列表)。getAggregations() 方法向调用者返回一个 IAggrFunction 类型列表,使调用者知道此工厂可以生成的各个聚合的类型。调用者负责在列表上进行迭代,并调用 IAggrFunctions 方法来获得描述。对于我们创建的工厂,我们不关心这些描述,工厂将负责返回和维护此列表。

向 getAggregation() 方法传入聚合的名称。该方法获取一个名称并提供一个 IAggrFunction 结果,清单 显示了示例工厂。

清单 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. 创建新 IAggrFunction 实现

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

IAggrFunction 类具有两项任务:它将自身描述为工厂可以创建的聚合,它还会创建 Accumulator 类的实例来为您的聚合执行实际工作。清单 给出了代码。


清单 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 下拉列表中显示的聚合的各个方面,比如数据类型、标题和描述信息。这 个方面有必要进一步解释一下。首先是 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. 测试插件

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

图 显示了一个简单报告,可以根据该报告来测试插件。将一个聚合组件插入到此报告的表尾。

图 9. 向报告添加聚合

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

在 Aggregation Widgets 下拉列表中,选择 Basic Word Count 聚合器并输入列表达式,以指向包含想要统计的句子的列,如图 10 所示。


图 10. Aggregation Builder

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

运行报告并验证结果。图 11 显示了生成的报告。


图 11. 报告结果

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


上面的例子是BIRT扩展点中相对简单的情况,但实现扩展点的过程却是一样,都是需要添加工程类,继承接口或者实现类,完成接口方法,添加插件依赖。后续的章节会讲解实现BIRT-ODA数据源扩展,XML emitter扩展,chat扩展等等。