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在表示层中构建用户界面有以下原因:
表示层也包含了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可以在别的产品上使用它。
单元测试在任何软件开发中都是非常重要的一个环节,即使是在软件的客户端也不例外。很多时候,应用程序的界面开发人员发现很难对代码做单元测试。通 常,这是因为表示层和应用逻辑紧密耦合从而使得单元测试代码的开发非常复杂和难于维护。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的测试用例:
public class RapJUnitTest extends RAPTestCase { public void testOpenView() { try { IWorkbenchPage page = getPage(); page.showView( "org.eclipse.rap.demo.DemoTreeViewPartI" ); } catch( PartInitException e ) { e.printStackTrace(); } assertEquals( 1, getPage().getViewReferences().length ); getPage().hideView( getPage().getViewReferences()[ 0 ] ); assertEquals( 0, getPage().getViewReferences().length ); } private IWorkbenchPage getPage() { IWorkbench workbench = PlatformUI.getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); return window.getActivePage(); } }
这个例子展示了如何测试一个实际的UI组件来验证可视视图的数量。而这也正展示了如何正确地测试基于RAP应用程序测试的一个步骤,然而,它并没有 提供自动化用户驱动交互。通过模拟一个用户点击按钮或者在输入框中键入值这样的测试UI的能力将会是CAS在未来所研究的目标。
除此而外,RAP还提供了还提供了用SWT构建的一个超大的组件子集,称为RAP控件工具箱,或者称为RWT,这套工具箱可以满足许多应用程序的需 要。然而,当有“标准”以外的需求时,Eclipse RAP也支持开发和使用定制组件。开发定制组件的第一步是确定这是一种什么类型的控件,在RAP中,有两种控件,izhong是“复合”式 ("compound")另外一种是“自构建”式("owner drawn")。复合控件是把已有的RAP组件组合到一起来提供一种新的UI功能。而自构建式组件则源于JavaScript,通常需要许多重型开发,有 时则需要第三方库。RAP开发向导提供了一个一步步教你如何创建“自构建”定制控件的教程,教程中用截屏和例子代码阐述了整个过程。对于定制组件的开发流 程,教程中列出了四个主要的步骤:
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的课程。
阅读英文原文 :Case study: Eclipse Rich Ajax Platform Use at CAS Software AG 。