简介
CAS Software AG 是来自德国 Karlsruhe 的一家软件公司,创建于 1986 年。该公司专注于 CRM(客户关系管理)领域,尤其是在 SME(中小企业)方面。近年来 CAS Software 的软件产品在 CRM 领域获得了非常好的声誉,包括他们在特定领域诸如面向教育、自动代理权和基于会员的组织或者协会等的 CRM 产品。
近来 CAS Software 正在开发被称为 CAS PIA(个人信息助理)的一个产品,这个产品会以 SaaS(软件即服务)的方式发布,这也是他们首个以这种方式发布的产品。该产品使用了许多技术,我们会在以后作详细介绍。这篇案例研究的重点将会放在 Eclipse RAP(富 Ajax 平台)以及它是如何应用到 CAS PIA 架构中的,同时也会涉及到 RAP 的一些有趣的应用、CAS 在使用它的过程中的一些个经验教训以及未来他们的产品的发展方向。
范围
CAS Software AG 为自由职业者以及中小企业开发 CRM(客户关系管理)软件。对 CAS 来说,他们把软件的受众定位在那些不使用特定 CRM 应用、而是更倾向于用工具和应用的组合来跟踪他们的客户、市场等的用户。CAS 认为对那些可集中而易于访问的客户信息管理软件,市场将会有很大的需求。在特定行业内,已经有基于桌面的应用,然而这些应用仅仅提供局限于 CRM 专有的功能。通过使用诸如 Eclipse RAP 和 Eclipse Equinox 之类的技术,CAS PIA 可以开发出不仅提供“标准”的 CRM 功能,而且还可以有管理市场战略、电子邮件整合以及个性化信件等功能的应用,而所有这些都被放入一个干净而模块化的软件包之内。
通过在用户界面开发中使用 Eclipse RAP,CAS PIA 提供了一个使用户感觉非常友好的桌面风格的界面体验。用户界面根据人类工程学(ergonomics)来开发,使用了人们熟悉的窗体部件和行为,比如拖放等等用户对 web 应用程序所期望的很多东西。另外,在线功能使所有同一公司内的同事可以通过该应用来管理委派、任务和文档,也可以进行其他的重要工作流程比如地址转换和路径计划。在下一章中,我们将深入到 CAS PIA 的开发架构中来看看开源软件在当中如何起到至关重要的作用。
解决方案概述
CRM 解决方案已经出现好几年了,桌面的和在线的都有,在最近一段时间里功能变得非常强大。用户在使用它们时的期望远远超出了基本功能,诸如报表、安全、亲和的外观和体验以及反应迅速的用户界面。基于许多用户对 CRM 应用的期望和需求,CAS 选用开源软件作为他们整个解决方案的基础。
从设计角度来讲,CAS PIA 是一款易于扩展的 web 应用程序,它可以利用多个服务进程,而这些服务进程可以分担访问压力和提供冗余。每一个服务进程都运行在作为应用程序服务器的 Apache Tomcat 之上,包含了基于 RAP 的应用层和一个服务核心。应用层负责展示用户界面和处理用户请求,而服务核心则提供商业逻辑和数据库访问。
CAS 选用基于 web 的应用程序,从而使得用户可以不必担心安装、硬件成本和配置以及数据的安全。而且,基于 web 的应用可以使用户在任何地点来访问 CAS PIA,而不必在每台计算机上安装重客户端。作为 web 应用前端的表示层使用了 Eclipse RAP 来开发。RAP 项目主页把它描述称为一个为开发人员提供了下述功能的框架:
通过使用 Eclipse 开发模型、基于 Eclipse 工作台扩展点的插件以及用 SWT API(以及 JFace)开发的组件工具箱来构建基于 Ajax 技术的富 web 应用 … RAP 非常像 Eclipse RCP,但是它不是在桌面计算机上启动,而是运行在一台服务器上,可以被标准浏览器访问。这主要是因为它提供了一套特殊实现的 SWT(一个 SWT API 的子集)。( http://www.eclipse.org/rap/about.php )
下面是 Eclipse RCP 和 Eclipse RAP 的一个简单架构对比图。
CAS PIA 用 Elipse RAP 在表示层中构建用户界面有以下原因:
- 用户感观 - Elipse RAP 可以构建出非常符合人体工程学而且可切换主题的富用户界面,已经非常类似于胖客户端的感受。
- 开发效率 - AJAX 和 JavaScript 被包装成对开发者透明的组件, 从而使得程序员可以用他们熟悉的 Java 类库和 IDE 来开发。
- 易于扩展 - 尽管 RAP 使程序员可以不直接使用 JavaScript、HTML 和 CSS 来开发,但是它也提供了足够的可扩展性,使定制的组件和风格可以毫无问题的加入到应用当中。
- 工程质量 - Elipse 和它的产品族拥有最好的软件设计和体验,RAP 也不例外。
- 单一代码库 - RAP 能够被编译为 AJAX 或者 RCP 应用程序。
表示层也包含了 OSGi 运行时环境,这为它在别的 CAS 产品中的使用提供了良好的模块性和复用性。CAS 选择 Eclipse Equinox 项目作为他们实现 OSGi 的工具,定义如下:
…一个 OSGi R4 核心框架规范的实现,即一组实现了若干可选的 OSGi 服务和其它架构的软件包,可以运行在基于 OSGi 的系统上。 总的来说, Equinox 项目的目标是成为一流的 OSGi 社区和使 Eclipse 成为界面组件视觉化的开发工具。
通过利用 Equinox 提供的分离机制,CAS 已实现了自己的核心模块,这些模块包含了许多软件包,这些包可以作为通用组件应用到不同的应用程序中。每个模块都提供了一些扩展点,通过这些点,根据所开发的不同应用的需求,可以实现不同的特定的行为。例如,用户管理组件可以用在许多应用程序当中,而联系人管理模块就比较特殊,只会被用到 CRM 相关的应用中。OSGi 提供的这种扩展性使模块很容易被扩展,比如在构建和部署阶段。
CAS PIA 的另一部分是商业逻辑和典型的服务器端相关功能,即服务核心或者 EIM(企业信息管理)。设计和开发 EIM 是把它作为 CAS 整个产品线的核心。服务核心提供了通过 Sun JAX-WS、RMI 和 REST 服务来远程访问的功能,核心同样也利用 Spring 框架设计成组件化的风格,都是可以被扩展的。
持久层用了 MySQL 数据库,同时也包含了 CAS 特别开发的定制组件。定制组件包含了一个可扩展的数据模型、一套定制的查询语言(CAS-SQL)和一个权限管理组件。该权限管理组件利用 ACEGI 框架来进行用户鉴权,也对数据库层的每个对象都提供了 ACL(访问控制列表)。这套权限管理系统和 Oracle 的 OLS 比较类似,而该系统还支持 MySQL 之外的其它数据库,从而使 CAS 可以在别的产品上使用它。
RAP Eclipse RAP 的单元测试
单元测试在任何软件开发中都是非常重要的一个环节,即使是在软件的客户端也不例外。很多时候,应用程序的界面开发人员发现很难对代码做单元测试。通常,这是因为表示层和应用逻辑紧密耦合从而使得单元测试代码的开发非常复杂和难于维护。CAS 的程序员们设法把尽量多的逻辑都放在服务器端,从而使单元测试(代码)非常健壮。然而,不是所有的东西都可以放到服务器端,而这也是为什么好的 UI 设计成为一个很重要因素的原因。
通过用通用设计模式比如 MVC、表示层模型(Presentation Model)、模型视图代理(Model View Presenter)等等来实现用户界面,将视图从逻辑当中解耦出来,从而使单元测试变得相对容易。即便进行了良好的设计,也还是有很多的问题需要面对,尤其是 RAP 用户界面的测试。首先,RAP UI 组件包含了一个 Java 层和一个 JavaScript 层,这意味着有两个部分的代码需要测试。 Qooxdoo ,即 RAP 使用的 Ajax 应用程序框架,提供了类似于 JUnit 和 JSUnit 的单元测试工具。CAS 利用这些工具来对组件的 JavaScript 层进行测试,用 JUnit 来测试 Java 层。下面是 CAS 提供的一个单元测试代码,展示了对定制组件 JavaScript 层的测试。
/** * Memory leak test. * * Creates and disposes an objects, and checks if there are some leaking instances. * * @type member * @return {void} */ testMemoryLeak : function() { var ms1 = de.tests.MemoryLeakUtil.getMemorySnapshot(); // create var dc = new de.cas.qx.ui.widget.calendar.datechooser.DateChooser(); qx.ui.core.Widget.flushGlobalQueues(); // dispose dc.dispose(); var ms2 = de.tests.MemoryLeakUtil.getMemorySnapshot(); var msg = de.tests.MemoryLeakUtil.checkMemoryLeak(ms1, ms2); this.assertEquals("", msg, "There are some leaking objects!"); },
这个特定测试试图找到由 DateChooser 组件引起的潜在的内存泄露(DateChoose 是 CAS 开发的定制组件中的一个)。 MemoryLeakUtil 类是一个 CAS 创建的定制工具类,它使用了 Qooxdoo 提供的一些功能,比如列出内存中的所有对象。通过 Qooxoo 提供的功能,他们可以轻易的对内存泄露问题来做测试,而这类问题是在 JavaScript 组件开发中很常见的。在测试 RAP 用户界面时需要面对的另外一个问题是处理 UI 的异步和动态的状态。有一些工具可以用来记录用户界面并且可以把这个过程存储起来,从而可以反复运行。这种类型的测试有助于检查 UI 的行为和交互,仿佛是有用户在真正使用它,但是它们也有局限性。在 CAS 对 web 应用程序测试工具做的大致评估中,他们还没有发现一款工具可以处理异步和非基于页面的用户界面,如遇到基于 Ajax 的应用程序,它的内容是动态装载的的而非改变整个页面。
单元测试中有时也会遇到的一个问题是对服务器和 / 或数据层进行测试。通常单元测试代码直接与服务器、数据库等直接通信来完成它们的测试。这种类型的测试有其缺陷,CAS 的开发者们也遇到过,单元测试由于需要和其他层的通信而变得很慢。一个通常的的解决办法是用假对象,在测试中用假对象来代替“真对象”。在 java 中有很多假对象的框架,包括 Mockito 、 EasyMock 和 JMock ,它们用来简化假对象的创建过程。对 JavaScript 来说,也有这样的假对象框架比如 JSMock 和 Mock4JS 。
之前您看到了用于测试 JavaScript 层的单元测试代码,之后您将会看到一段测试 Java 层的例子。对 Eclipse 1.1 来说,这个框架框架基本上包含了相当于 JUnit 的测试的功能,不同的是它可以使需要 OSGi 环境的测试正常运行。如果您需要执行期间更新 UI 的单元测试,您可以非常简单地从org.eclipse.rap.junit.RAPTestCase
扩展。但是,如果对单元测试来说不需要更新用户界面,那么相应地,你可以扩展 JUnit 的org.junit.TestCase
类。下面是一个关于包含了用户界面交互的 RAP 的测试用例:
<span color="#800080"><b>public class</b></span> RapJUnitTest <span color="#800080"><b>extends</b></span> RAPTestCase { <span color="#800080"><b>public void</b></span> testOpenView() { try { IWorkbenchPage page = getPage(); page.showView( "<span color="#0000ff">org.eclipse.rap.demo.DemoTreeViewPartI</span>" ); } <span color="#800080"><b>catch</b></span>( PartInitException e ) { e.printStackTrace(); } assertEquals( 1, getPage().getViewReferences().length ); getPage().hideView( getPage().getViewReferences()[ 0 ] ); assertEquals( 0, getPage().getViewReferences().length ); } <span color="#800080"><b>private</b></span> IWorkbenchPage getPage() { IWorkbench workbench = PlatformUI.getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); <span color="#800080"><b>return</b></span> window.getActivePage(); } }
这个例子展示了如何测试一个实际的 UI 组件来验证可视视图的数量。而这也正展示了如何正确地测试基于 RAP 应用程序测试的一个步骤,然而,它并没有提供自动化用户驱动交互。通过模拟一个用户点击按钮或者在输入框中键入值这样的测试 UI 的能力将会是 CAS 在未来所研究的目标。
定制用户界面组件
除此而外,RAP 还提供了还提供了用 SWT 构建的一个超大的组件子集,称为 RAP 控件工具箱,或者称为 RWT,这套工具箱可以满足许多应用程序的需要。然而,当有“标准”以外的需求时,Eclipse RAP 也支持开发和使用定制组件。开发定制组件的第一步是确定这是一种什么类型的控件,在 RAP 中,有两种控件,izhong 是“复合”式 (“compound”) 另外一种是“自构建”式 (“owner drawn”)。复合控件是把已有的 RAP 组件组合到一起来提供一种新的 UI 功能。而自构建式组件则源于 JavaScript,通常需要许多重型开发,有时则需要第三方库。RAP 开发向导提供了一个一步步教你如何创建“自构建”定制控件的教程,教程中用截屏和例子代码阐述了整个过程。对于定制组件的开发流程,教程中列出了四个主要的步骤:
- 为组件创建一个运行在服务器上的 Java 实现
- 为组件创建一个运行在浏览器上的 JavaScript 实现
- 用 Java 创建一个适配器,这个适配器把 JavaScript 组件和 Java 组件连接起来
- 通过在
org.eclipse.rap.ui.resources
扩展点上增加插件的方式注册该 JavaScript 文件
CAS 的开发人员必须开发一些自定义控件包括一个日历、日期选框、工具条和可折叠的导航控件,看起来像 Microsoft Outook。这个日历和工具条就是用 JavaScript 加上 CSS 和 HTML 开发的“自构建”组件的例子,转化而成为 CAS PIA 所用的 RAP 组件。Qooxdoo 提供了很多功能来开发控件,这些功能可以大大的降低开发的难度。下图是展示了一组“自构建”组件的截屏,特别是一个日历和一个工具条。
可以看到日历组件提供了很多功能比如左上角的一个迷你日历,中间的一个比较详细的日历,可以加入任务,而且可以定制视图来显示(例如,“所有的任务”)。这个特殊部件由大约20000 行代码构成,实现它需要大量时间和精力。上图中所示的另一个“自构建”组件是一个工具条,它提供的功能类似于很多应用例如 Microsoft Office 和Microsoft Outlook 的工具条。组合组件的例子是一个时间选择器,我们可以在CAS PIA 中看到它,如下图所示。
这个复合组件由一组控件包括一个对话框,若干按钮以及可选框构成, 他们一同构建了这个时间选择器。在CAS PIA 的拷屏图中另外值得注意的一点是应用的整体样式或者说主题。RAP 通过使用层叠式样式表(CSS)提供了主题功能,同时使应用可以接受加在 org.eclipse.rap.ui.themes
扩展点和plugin.xml file
扩展点上的扩展。
开发定制的 RAP 组件时,在设计和开发阶段必须对下面几点加以考虑。首先,开发人员必须熟悉 HTML、JavaScript、CSS 和 Qoodoo。我提到这个是因为 RAP 的一个优越之处就是开发人员可以用 Java 来编程而可以避开 JavaScript,但是在开发定制组件时却不是这样。其次,开发人员必须设法使控件具有跨浏览器特性。写过 RAP 核心组件的开发人员竭尽全力来确保控件的浏览器兼容性,而在未来版本的 Qooxdoo 中有望在这方面得以增强从而使开发人员可以免于考虑浏览器兼容性问题。最后,另外一个需要注意的问题是在 RAP 中的 Qooxdoo 和你从网站上下载的不是同一个版本。极端情况下,对 RAP 的开发人员来说,这意味着一些特定功能和类可能不能使用,尽管它们出现在 Qooxdoo 的 API 中。
开发中遇到的问题
对开发人员来说任何新技术都一定要有一个学习曲线,发展过程中也会有很多问题。在 CAS PIA 的开发过程中开发团队陷入了一些与性能和部署相关的问题当中。
他们马上遇到的第一个问题就是客户端和服务器端都出现较低的性能和高的资源开销。CAS 利用可以复用 GUI 控件而不是反复创建它们的对象池和缓存来提升一些性能。尽管 CAS 所做的努力有所帮助,但是对于完全解决他们在 Internet Explorer 上的性能问题还远远不够,这也使得 CAS PIA 不能支持 IE。然而 CAS 对短期内 Qooxdoo 框架的性能提升和 Internet Explorer8 的即将发布对 CAS PIA 表现出可接受的性能和对 IE 的支持相当有信心。另一方面,在别的浏览器上特别是 Firefox,都已经在近期取得性能和资源开销问题方面的提升。
另外一个令人头痛的问题是用一种连续累计的构建过程开发和部署整个应用程序的 RAP 组件。由于 CAS 选择将 Eclipse Equinox 部署到 Tomcat 中而不是将 web 服务器嵌入到 Equinox,所以这是唯一的问题。CAS 使用了 Eclipse 中的 Releng- Tools,这个工具可以支持夜间自动构造,然而它们在使用 Ant 的过程中发现文档太少而且有很多奇怪的问题(比如,动态生成构建脚本)。最终确保夜间构建的正常运行花费了大量的监控和测试。
与此同时 CAS 不得不解决将 Equinox 部署到 Tomcat 中的问题。对这个配置问题提出的解决方案是,生成一个单独的 WAR 文件,这个文件中包含了所有的商业组件、运行时环境、Equinox 和 RAP。但是,CAS PIA 也需要 EIM 这么一个非 OSGi 组件和 RAP 部分一起集成到应用程序当中,从而使得两个部件之间可以不通过 web 服务和 RMI 直接通信。解决这个问题需要分两步,首先必须把 EIM 服务器组件放到 WAR 文件的"lib"目录中。第二步涉及到对 web.xml 中 servlet bridge 的特殊配置。CAS 用到了 servlet 桥中的“ extendedFrameworkExports ”参数,这个参数能使 EIM 和 RAP 组件根据需要集成在一起。
经验教训
CAS Software 积极致力于开发和部署 Eclipse RAP 应用程序,即便在开始的时候碰到很多问题,他们仍然非常乐于使用 Eclipse RAP 来开发产品。他们发现用 Eclipse RAP 后开发人员的效率得到显著提高,这主要是因为 Java 程序员已经习惯于 Eclipse 的集成开发环境、调试工具和组件模型。
一旦 CAS 克服了以上提到过的问题而走过了陡峭的学习曲线,每个人都会乐于使用 RAP 来做开发。CAS 希望 RAP 在未来产品中增加的唯一功能是从服务器端来触发客户端动作的能力。目前 CAS PIA 使用自主开发的一套方案,其实实际上称不上真正的解决方案,但 CAS 对 RAP 的未来充满信心。
未来发展方向
CAS Software AG 目前在中小企业 CRM 市场上居于领导地位,他们计划到 2010 年时把这种领导地位拓展到整个欧洲。CAS PIA 在 2009 年第一季度将会面试并且推广。最终目标是成为 SaaS CRM 产品欧洲地区供应商的前 20 位。
CAS 会继续在使用和支持 Eclipse RAP 上发挥他们重要的作用,他们还将于 2009 年 2 月在匈牙利的赛格德大学开办有关 RAP 的课程。
参考链接
- CAS PIA
- Eclipse RAP Book (2008 年 12 月)
- http://rapblog.innoopract.com/2007/12/rap-deployment-part-2-deploying-your.html
- http://www.eclipse.org/equinox/server/http_in_container.php
- GUI 测试工具
阅读英文原文: Case study: Eclipse Rich Ajax Platform Use at CAS Software AG 。
感谢曹云飞对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。
评论