RCP
富客户端通常是指具有独立用户界面的客户端程序。富客户端程序可以是依赖于服务器的前台界面,也可以是独立运行的软件系统,与传统客户端程序相比,富客户端程序的功能更加强大,用户界面体验也更为丰富。Eclipse富客户端平台(Rich Client Platform,RCP)基于插件技术体系,为开发者提供了强大和方便的功能。
RCP将调试、版本控制等模块从传统的Eclipse平台中剥离,仅保留了作为核心的运行时框架和SWT,JFace为基础的UI框架两大部分,同时将“帮助系统模块和自动更新模块作为可选项,搭建一个通用的程序开发平台。
RCP作为一个优秀平台,具有以下特点:
-插件化的架构使得程序结构更加清晰简练,易于修改和维护;
-图形界面技术基于SWT和JFace,所开发出的程序天然跨图形平台,而且具有和本地程序一致的显示效果;
-使用Eclipse的UI组件(透视图、编辑器、视图、向导页、帮助系统等)可以轻易的设计功能丰富且美观的界面;
-拥有强大的Eclipse开源社区的支持,开发者可以自由选择数量繁多的各种免费插件无缝集成到程序中以增强程序性的功能。
-最重要的一点是RCP是一个完全免费的平台,无论是商业用户还是个人用户,只要遵循EPL,都可以合法地将其用于包括商业软件在内的各种开发。
1.RCP平台架构
---------------
Eclipse RCP主要由三大部分组成:
第一部分,由Equinox和Runtime组成,负责管理整个插件结构体系。其中Eclipse Runtime模块负责解析和管理插件之间的扩展点和扩展的相互关联;而Equinox则管理插件的版本,依赖关系及动态的载人、卸载等内容。
在早期的Eclipse设计中,没有Equinox这个模块。那时,两个部分的工作都是由Eclipse Runtime模块完成。不过,当时的Eclipse平台不能支持动态的载人或卸载插件功能。安装新的插件或进行自动升级后,都必须重新启动工作台才能使新的安装部分生效。
自Eclipse3.0开始,平台的开发者将目光转向了OSGi框架。OSGi(Open Service Gateway initiative,开发式服务网关协议)框架式一套基于Java的动态组件模型管理框架。它是由IBM,Apache等多家机构所组成的OSGi联盟所提出的一套开放式标准。J2SE规范中缺乏对组件编程的支持,这套标准恰好对此做了补充。
OSGi框架着眼于组件化编程,为传统的Java执行环境提供了三个方面的服务支持:
1.模块化(Modules)。OSGi框架对应基于J2SE的类型读取机制(Class loading policy)进行了加强,加入了模块化的概念。在传统的Java类型读取机制中,一个程序通常拥有一个单一的、包含所有类型和资源的类型读取器,模块层则为每一个模块提供独立的读取器,这意味着用户可以创建只在模块内可见的类、对象或资源,模块层还为模块之间的访问提供了完善的控制机制。
2.生命周期管理(Life Cycle)。生命周期管理层负责在运行时对组件进行管理,通过这一层提供的服务,开发者可以动态地添加、删除、升级、启动或禁用各个组件。
3.服务注册表(Service Registry)。服务注册表帮助动态变化的组件维护互相引用的关系。组件之间经常需要相互交互,如果通过传统的做法--共享类型和对象来完成这种交互,在其中一方的组件被动态删除或禁用时可能会遇到问题,服务注册表提供了一个综合化的模型来完成这项工作,在服务注册表中,每一个需要共享的Java对象都是一项服务(Service),当某一项服务可用或不可用时,服务注册表都会发出对应的事件,组件可以通过这些事件了解服务的变化并相应的做出反应。
OSGi的核心是一个符合java规范的可执行环境,如J2SE,J2ME等;OSGi提供三项服务在Java可执行环境的基础上为应用程序开发者编写的各个组件提供支持。
在OSGi框架下,应用程序不再是一个完整的集合,而是由多个组件组成,这些组件拥有各自的生命周期,独立地完成应用程序的一部分工作,应用程序需要调用OSGi框架的服务功能以组织和管理这些阻聚剂,这与Eclipse平台的插件思想是相似的,基于这种相似性,Eclipse的开发者就尝试把OSGi引入插件体系。
自3.0开始,开发者们基于OSGi框架对旧的插件管理部分做了重构,所形成的新的插件管理框架被称为Equinox,它遵循OSGi Release 4规范。在Equinox中,组件(物理上通常表现为一个JAR文件)被称为“束”(Bundle),插件、段及功能部件等都是一个束,合法的束需要按照Equinox所要求的格式提供描述及自身的信息,对于JAR文件来说,这些信息一般存储在压缩包中META-INF目录下的MANIFEST.MF文件中,它们与组件的XML描述(插件的plugin.xml段的fragmeng.xml及功能部件的feature.xml等)一起构成了一个完整的Eclipse插件描述。
在新的框架中,对一个插件的分析过程是由Equinox+Runtime共同完成的,Equinox读取MANIFEST.MF文件以确定插件的版本号、相互依赖关系等内容,而Runtime则负责读取plugin.xml并对插件的扩展点、扩展等内容进行维护和管理,两者是相对独立又相互协调的关系。
第二部分,是UI相关的插件,由SWT和JFace,以及基于其上的Eclipse UI框架构成。Eclipse UI框架的插件包含了透视图、编辑器、视图和操作集等扩展点,另外,如首选项,向导页等功能也包含在Eclipse UI框架中,在RCP程序中也同样可以使用这些功能。
在普通插件开发过程中,工作台窗口是由Eclipse平台提供的,用户只需要开发和管理自己的编辑器、视图等组件,而在RCP晨曦开发过程中,工作台窗口也需要用户自动生成,除此之外,为RCP开发图形界面与为插件开发图形界面的工作完全相同,用户可以很方便的利用RCP将已开发的插件改造成RCP程序。
另外,用户也可以在RCP程序中使用工作台的一些标准的操作,如“窗口”菜单中的“首选项”操作和帮助菜单中的“软件更新”操作等,这些操作会触发工作台中特定用途的标准对话框,用户可以通过使用它们丰富自己的程序。
第三部分,是自动升级、帮助系统等可选模块,这些模块属于辅助部分,它们可以在RCP程序中添加丰富的功能。
----------------------------------------------------------------------------
2.RCP程序的结构
----------
Eclipse的一切基于插件,RCP程序也不例外,通常所说的RCP程序开发,事实上就是开发一组插件,并将它和RCP平台一起发布出去,而RCP插件与普通插件的区别,就在于org.eclipse.core.runtime.applications这个扩展点。
applications扩展点是Eclipse平台运行的“入口”,可以将它看做RCP程序的Main函数。默认情况下,启动eclipse.exe时,平台会根据{eclipse根目录}/configuration/config.ini文件中设定的eclipse.application属性的值来决定启动的入口点,可以在这个文件中修改设定的值,也可以在运行eclipse.exe时使用参数-application APP_EXTENSOIN_ID来启动其他的入口。
Eclipse IDE安装完成后,默认的启动入口点是id为org.eclipse.ui.ide.workbench的applications扩展,它负责打开一个工作台窗口,普通插件不需要自己的入口点,用户调用这个插件时,工作台会负责将插件载人,然而该默认入口点是IDE插件的一部分,是不包含在RCP平台中的,因此RCP插件必须扩展applications以声明自己的入口点。是否有自己的applications扩展作为入口点,是RCP插件与普通插件的最大区别。
RCP应用程序的启动过程:
1)执行eclipse.exe,初始化插件框架;
2)框架通过制定的applications扩展,找到并运行RCP插件中的IApplication实例;
(如果框架调用的是Id为org.eclipse.ui.ide.workbench的applications扩展,启动的将是Eclipse IDE;而如果调用的是RCP程序提供的applications扩展,启动的就是开发者自己编写的RCP程序了。因此本质上看,Eclipse IDE就是一个复杂的RCP程序)
3)RCP插件在入口点中创建并打开一个工作台窗口,在这个过程中,需要为该工作台窗口指定一个透视图Id(ApplicationWorkbenchAdvisor.getInitialWindowPerspectiveId())
4)工作台窗口启动后,会根据指定的初始透视图Id启动透视图,透视图又会启动其中包含的视图、编辑器等组件,这样就 得到了一个用户可以操作的界面
另一个启动相关的扩展点是org.elclipse.core.runtime.products,products扩展点用于指定对工作台的装饰(如窗口图标、标题等),每个products扩展唯一地关联着一个applications扩展,因此通过products扩展也可以找到启动的入口点,如果通过products启动的applications创建一个工作台,那么在products中指定的装饰就会应用到工作台窗口上。Eclipse IDE也有默认的products扩展,它的id是org.eclipse.sdk.ide,对应到默认的applications扩展。
在config.ini文件中,可以用eclipse.products属性指定通过某一个products扩展启动程序,通常一个RCP程序只需要一个products扩展,不过开发者也可以在RCP中定义多个products扩展,并根据需要选择启动不同的扩展以改变程序的外观。
从Eclipse 3.1开发,EclipseIDE提供了一个更加简单高效的方法供开发者生成RCP程序的产品配置(Product Config)。通过产品配置文件编辑器,开发者不再需要手动项products扩展点添加属性,可以使用图形化的界面方便地配置这些信息。
applications扩展中将Application类指定为启动入口,RCP程序启动后,会调用该类的run方法,
public class Application implements IApplication {
public Object start(IApplicationContext context) throws Exception {
Display display = PlatformUI.createDisplay();
try {
//动工作台的操作,并提供了一个工作台配置类的实例
int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART)
return IApplication.EXIT_RESTART;
else
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
public void stop() {
final IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null)
return;
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
public void run() {
if (!display.isDisposed())
workbench.close();
}
});
}
}
在入口点run方法中,代码调用了PlatformUI的静态方法createAndRunWorkbench来创建一个工作台,这个方法同时需要一个WorkbenchAdvisor的对象来对所生成的工作台进行配置,这个对象由ApplicationWorkbenchAdvisor类完成,在三个配置类中,它第一个被调用:
public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor{
//调用一个工作台窗口配置类(WorkbenchWindowAdvisor的子类)来完成工作台窗口的配置
public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
return new ApplicationWorkbenchWindowAdvisor(configurer);
}
public String getInitialWindowPerspectiveId() {
return PerspectiveUtil.XXXX_PERSPECTIVE_ID;//为工作台窗口配置默认的透视图ID
}
public boolean preShutdown() {
return true;
}
}
工作台窗口配置ApplicationWorkbenchWindowAdvisor 继承自WorkbenchWindowAdvisor ,在其中可以配置窗口标题,是否显示菜单栏、工具栏、状态栏等与窗口相关的内容,同时还提供了一个操作配置类ApplicationActionBarAdvisor,用来为窗口初始化工具栏(工作台窗口中的工具栏为CoolBar)和菜单内容。
public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
super(configurer);
}
public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
return new ApplicationActionBarAdvisor(configurer);
}
public void preWindowOpen() {
IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
configurer.setInitialSize(new Point(400, 300));
configurer.setShowCoolBar(false);
configurer.setShowStatusLine(false);
configurer.setTitle("Hello RCP"); //$NON-NLS-1$
}
}
ApplicationActionBarAdvisor 类负责向工作台窗口的菜单栏、CoolBar和状态栏上添加操作,开发者可以重载fillMenuBar,fillCoolBar和fillStatusLine三个方法来完成;重载makeActions方法可以创建操作Action添加到菜单、CoolBar和状态栏的ContributionManager上去,不过出于灵活性考虑,通常推荐使用actionSets扩展点创建Action,而不是在这里直接硬编码。
public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
super(configurer);
}
protected void makeActions(IWorkbenchWindow window) {
}
protected void fillMenuBar(IMenuManager menuBar) {
}
}
--------------------
3.发布RCP项目
-----------
发布RCP工程之前,首先需要创建一个产品配置文件。new-->Product Configuration为一个以.product为扩展名的产品创建配置文件,打开配置文件进行相关项目的配置
设置好配置项后,就可以导出RCP程序了,选择导出目录后,就可以将RCP程序导出成独立的可执行程序。发布出的RCP程序以一个目录的形式存在,开发者可以手动将其打包成ZIP文件发布,也可以使用第三方的安装程序制作软件(如InstallShield等)将其制作成安装程序发布给最终用户。