本人在developerWorks上投稿的一篇文章,写的一般,收录在这:
http://www.ibm.com/developerworks/cn/lotus/domino-orm/
Domino 数据库与关系型数据库之间数据的流通性是 Domino 用户所面临的一个普遍问题。与目前通用关系数据库相比,Domino 数据库有其独特的特点:它不像关系数据库那样有一种通用的脚本化的查询语言(即 SQL),而是基于共享文档的思想建立起来的,存储的基本单元是文档,用户通过特定的视图来得到所需的文档集合。
由于 Domino 数据库管理机制自身没有提供脚本式的接口,用户往往只能利用 Domino 提供的 API 编写面向特定应用的程序来读出或者写入数据,与关系数据库交互。这时,这些程序的灵活性和可扩展性将面临很大的挑战,因为现实世界所需要的数据格式往往是不断变化的。在关系数据库中实现这种变化很容易;但是要让关系数据库与 Domino 数据库之间的接口程序也能满足这种不断变化的需求就变得异常困难。
一般来说,出于项目成本的考虑,客户往往不希望在他们具体的应用项目中实现某种通用的、平台级的解决方案,来满足这种数据格式不断变化的需求,因此,这些面向当时需求开发出来的接口程序不得不在以后的维护过程中不断重写以适应变化的数据格式,从而造成不同程度的 IT 资产重复投资和浪费。
Domino 在其二十多年的发展历史中推出了一些周边产品和技术试图解决这个问题,本文将在下面一节中详细分析这些产品和技术的特性及其局限性。笔者认为,由于 Domino 数据库的特殊性,不能期望仅仅通过一些自动化的产品和工具来完全解决这个问题,而应该综合多种技术,系统化的考虑这些问题。本文介绍了笔者设计的一种解决方案,即为管理员提供易于操作和便于管理的图形化界面工具,通过用户(尤其是管理员用户)的介入来解决某些问题,本文将在第三节中详细讨论这一方法。
本节通过对 Lotus Domino 现有的编程接口和相关工具进行系统化的梳理,来分析一下它们各自在解决本文提到的问题时能起到的作用。这些编程接口和工具包括:
首先,我们来分析 Lotus Domino 提供的 C/Java 编程接口。这套接口对于比较简单的应用是非常方便的:比如按照文档表单中的某些简单域(如文本域)从数据库中查询文档,得到结果文档集合,再从结果集中依次分析文档表单中的域内数据。另外,这两套接口也提供了查询文档数据库 schema 的方法,用户可以动态的查询到一个数据库中包含哪些表单,每个表单包含哪些域,然后根据这些信息来组织自己的查询。
事实上,当我们只考虑表单中包含有简单域的情况下,Domino 数据库的结构是可以和关系数据库类比的。一个 Domino 数据库在物理上是一个 NSF 文件,这个文件是一系列文档的集合。文档(Document)是基本的数据单元,包含着一个数据实例。这个特定的数据实例的数据结构是由事先设计好的表单(Form)来决定的。表单里包含着若干个表单域。表单域是最基本的数据,包括诸如文本域、选择框域等等。而文档实际上就存储了用户输入到各个域里的数据。
这样看来,我们可以把一个表单看做一张关系数据库表的 schema,表单里的域相当于关系表里的各个列。而一个文档就相当于关系表的一条记录。这样,Domino 数据库里所有属于同一个表单的文档集合就构成了关系数据库中的表。在 Domino 数据库中,每一个文档会有一个唯一标示(UID),就相当于关系表中的主键。用户可以在表单里用某些域来存储其他文档的 UID,那这些域就相当于关系表里的外键。通过主外键的关系就可以完成关系数据库里的一对多和多对多的复杂关系。
但是,当涉及到文档中的复杂域(富文本域)的时候,这样的编程接口就变得不是很灵活了。富文本域是最体现 Lotus Notes/Domino 产品特色的一个域类型。在这个域里面,用户可以用非常灵活自由的方法编辑文本,这和编辑微软 Office 文档类似,比如编辑表格、区段、插入图片、嵌入其它文本文件等等。这样,富文本域里面的数据实际上是一种用特定格式编码的文本文档,和微软的 .doc 类似。Lotus 开发社区把这种文档格式称为 CDData。Domino 提供了一定的编程接口来处理 CDData,比如分析其中的内容,在 CDData 和 HTML 之间相互转换等等。但是,由于 CDData 文档格式的复杂性,是不可能用一种简单通用的方法来对这种文档进行分析处理的。
举一例说明这种情况。用户在设计表单的时候,出于对富文本域进行自动化处理的需要,可以在该域中提供某种形式的模板,比如预定义一张表格,并根据业务需求要求不同类型的数据库用户输入时在表格的特定位置填入数据。而用户的自动化处理程序可以通过 Domino API 从 CDData 中分析这张表格,根据用户类型从不同的表格位置中得到相应的数据。
这样,用户的自动化处理程序就和这个富文本域的模板以及数据库用户类型这两个实体密切相关了。一旦,现实世界中的应用因为业务需求的变化需要改变这个模板,或者改变了用户类型和模板中表格位置的对应关系,那么,用户只有重写这个自动化处理程序来反映这种变化了。这个例子说明,单纯依靠编程接口来对这种富文本域进行自动化处理往往是不灵活和不具有可扩展性的。
其次,我们来分析一下 Lotus 提供的比较常用的用于数据处理和转换的工具:Lotus Enterprise Integrator。Lotus Enterprise Integrator 是 Domino 的一个非常优秀的输入工具,在 Domino 开发社区里得到了广泛使用。这个产品相当于 Domino 的一个数据源,可以以 Domino 为中心把其它关系型数据库中的数据吸收到 Domino 应用中来,从而为 Domino 提供强大的数据集成能力。另外,它和 Domino 产品有着很好的集成,管理员用户可以在 Domino 管理界面中通过图形化的方式来对它进行设置,简单方便。但是,它只解决输入的问题,不解决输出的问题。
我们再来分析一下 Domino 所提供的 REST Service 接口。REST service 是 Web 编程模式在经历了 CGI、Servlet/JSP、EJB 中间件和 Web service、Spring/Hibernate/Struts 等几代编程思想的进步和反思之后流行起来的新的编程模型,其特点可以总结为:简单、实用。所谓简单,是指它的基本思想及其简化:把所有的服务抽象为资源以及基于资源的几个基本操作,而每一种基本操作又可以和一种 HTTP 协议的操作相绑定,这样,应用程序从中间件层的角度看的时候已经简化到极致。所谓实用,是指 REST 抽象出来的这种资源的概念可以和关系型数据库有着天然的映射关系。这样以 REST 资源为基础来编写的应用程序框架和关系数据库的匹配也非常合适。这样这种新的编程模型是很实用的,无论从学习曲线、代码量、性能,等等各方面衡量,REST service 都有着突出的优势,因此得到了广泛的流行。
Domino 也提供了自己的 REST service 编程接口,并且这一接口在其随后的版本功能、性能各个方面都会越来越加强。Domino 把自身的设计元素和数据都提供为 REST 资源,如 Domino 服务器、数据库、视图和文档等等。用户可以用 REST 的方式对这些资源进行访问,得到相应的 JSON 对象,然后在 java script 程序中使用这些对象。正如本节前面所分析的,对于简单域的情况,使用 REST service,Domino 做的和关系数据库一样理想;但是,一旦涉及到对富文本域进行处理的情况,使用 REST 比前面提到的 Java/C API 而言没有任何改进。
笔者曾在 2008-2009 年对国内 Lotus 的一些客户就有关 Domino/Notes 的 IT 资产进行过一些基本的调查工作,发现这些客户在这二十年间往往都积累了成百甚至数千数量级的 Domino 应用,并且大多都在稳定的运行中。但是,随着新兴技术的不断涌现,这些企业迫切的需要重用这些已有的 IT 资产,最大程度地分析和挖掘其中存储的宝贵数据,并期望和其它新兴的 Web 平台技术(如 Portal、报表工具、Office 等)进行有效的集成。
对于相当数量的 Domino 应用程序,如果他们不涉及到富文本域的自动处理问题,那么,前文提到的从 Domino 到关系数据库的映射以及 REST Service 接口的方法已经能够比较方便的解决集成问题。但是,很多情况下用户会遇到处理富文本域的问题,需要处理的数据可能存储在富文本域中,甚至可能存储在富文本域中嵌入的附件中(如 Word 文档、PDF 文档、Excel 文档等)。下面举一例说明。
某公司用 Domino 应用作为公司的报表管理系统,它们的业务流程是:首先,公司定期下发 Excel 报表模板供全公司使用,这个模板里的数据定期会有微调。其次,基层的业务人员在每个周期的周期末要定期的填写报表,即在模板里面填写数据,然后新建一个 Notes 文档,在文档里也填好相应的数据,把这个 Excel 文件嵌入到这个文档中提交。最后,公司的信息收集人员在收集到所有的 Excel 报表之后,对这些报表进行手工汇总和处理,汇总的数据要存到关系数据库中。显然,随着公司规模的膨胀,这种手工的报表处理方式最终将不堪重负。
这个例子因为涉及到富文本域的处理问题而变得比较复杂。由于该公司的报表模板会有定期的微调,那就意味着,以当时的报表模板的数据结构为基础开发一套自动处理程序是无效的,因为这个数据结构会不断变动。笔者认为,最好的方法是为该公司的 Domino 管理员提供一套图形化的映射工具,这个映射工具能够很清楚地反映出作为源的当前 Domino 数据结构和作为目标的关系数据库的映射关系。一旦数据结构有变动,管理员可以自己对这套映射关系作出改变。
这套图形化映射工具可以根据管理员的输入生成数据映射规则,并保存在 Domino 数据库中。可以在 Domino 服务器中开发一个 agent 程序定期运行,自动解析这些映射关系,根据它们对 Domino 数据库中的相关文档进行分析,完成数据汇总工作,并将数据存储到关系数据库中。这样,如果数据结构没有变化,每次管理员只需要手动或自动启动这个 agent 程序就可以自动完成这种报表收集和整理工作。如果数据结构有变化,那管理员只需要根据变化的需求输入新的数据映射规则。
这样,通过提供图形化的映射工具,由管理员根据业务需求动态的设计映射结构来向关系数据库提供 Domino 数据的方法,可以帮助解决自动处理富文本域的问题。在构建图形化映射工具方面,Notes 8 提供的复合应用(composite application)提供了很好的支持。复合应用可以把来自不同进程的 Windows 窗口界面组合到同一个工作区里面,并通过动态连线的方式在不同窗口之间传递数据。另外,Notes 8 还提供了多种缺省的复合应用组件,包括 Symphony 容器组件、Notes view 容器组件、Web 容器组件等。用户也可以利用复合应用 API 开发自己的组件,构成面向自身业务应用的组件库。复合应用编辑器可以帮助用户用所见即所得的方式用复合应用组件搭建复合应用。
我们仍以上面的需求为例,可以利用 Symphony 容器组件显示用户的 Excel 报表模板,用 Notes 视图组件来显示并存储映射规则(每一条映射规则被存储为一个 Notes 文档)。我们只要再开发一个用来展示关系型数据库中表结构的组件,和一个用来输入映射规则其他信息的组件就可以构成这样一个图形化映射工具了。
下图展示了这个映射工具,在这个图中我们展示了如下几个组件:
在这个工具中,管理员的工作过程如下:首先在 Symphony 容器组件中打开 Excel 报表模板(Symphony 容器具有兼容 Office 文档格式的功能)。其次在关系数据库组件中选择目标关系表,这时关系表的所有列名、类型等信息都显示出来。接下来,用户可以在 Excel 模板中用鼠标标记他需要的数据所在的单元格或列,作为映射源。所选的单元格或列的位置信息通过复合应用连线传给映射规则生成器。之后,用户在关系数据库组件中选择作为映射目标的关系表域信息,同样,所选的关系表信息通过连线传递给映射规则生成器。最后,在映射规则生成器中,用户输入其他必要信息后,点击确认即提交到 Domino 数据库中,这时在映射规则管理器中可以看到新生成的映射规则文档。
为了适应 Excel 报表的多种映射形式,可以设计多种不同类型的映射规则,比如可以把报表中的多个单元格信息组合为目标关系表的一条记录;也可以把 Excel 报表上的各个列映射为关系表中的各个字段,这样 Excel 报表中的一行就对应了目标关系表的一条记录;也可以混合报表中的单元格信息与其他一些 Notes 表单的信息作为目标关系表的一条记录,等等。需要为每一种映射规则设计一个 Notes 表单。图形化映射工具的功能就是提供所见即所得的方式帮助管理员生成这些映射规则。通过这些映射规则来驱动 Domino 服务器上的 agent 程序来对 Domino 数据库中的文档进行分析、汇总,并将结果写入到关系型数据库中去。
通过这种方式建立起来的应用系统具有非常好的灵活性和可扩展性。从灵活性的角度来说,这种映射工具和这样的 agent 程序与具体应用的数据格式等等没有耦合,它完全可以适用于一个公司内部有类似需求的所有 Domino 应用。只需要管理员针对具体应用的业务场景为其制作特定的映射规则就可以,而这种制作过程完全是在图形化界面上用所见即所得的方式完成的。从扩展性的角度来说,如果现有的映射规则的类型不满足需求,那用户可以根据需求通过一定的开发工作来设计新的类型的映射规则就可以,这是一种增量式的开发,没有任何的重写、重开发的工作量。
综上所述,由于 Domino 数据库的存储格式等等特点,其与关系型数据库的数据转换系统往往比较复杂且很难保证应用系统的灵活性和可扩展性,应该用系统化的方法,综合运用多种手段来解决此类问题。本文提供了一种新的思路,即搭建一个图形化的数据映射工具,配合 Domino 上的 agent 程序,来构造一个灵活的数据转换平台,从而形成了一个极为灵活,并具有高度可扩充性的数据转换系统。Lotus Notes 的复合应用编程模式为搭建这样一种图形化映射工具提供了方便、快速的开发方式。复合应用本身提供了灵活的组件模型和组件装配编辑器,并提供了常用的桌面应用组件。利用复合应用可以快速的完成这种图形化工具系统的开发工作。