在此贴上我发表在2008年10月份《程序员》杂志的一篇技术文章。
在Web2.0大行其道的今天,有很多桌面应用程序已经运行到浏览器上面,这其中有Microsoft Office Live, Google Docs等等。自从Eclipse 3.0引入Rich Client Platform(后面简称RCP)以来,RCP应用程序得到了广泛的应用,自然,人们期望RCP应用程序也能够运行在浏览器上面,尽管这是一个挑战,但总是有人能挑战成功,Eclipse下面的子项目Rich Ajax Platform(后面简称RAP)就做到了,这篇文章就是告诉你如何用RAP将你的RCP应用程序移植到B/S架构上。
前提
l 熟悉Java语言
l 熟悉Eclipse IDE和RCP应用程序开发
l 机器上安装了Eclipse 3.3 或者 Eclipse 3.4
RAP简介
RAP使得开发人员只需要做很少的修改就可以将RCP应用程序移植到B/S架构,开发人员甚至不需要了解Web应用程序开发技术,他(她)依然可以用Eclipse开发模式来开发RCP应用程序,依然可以利用扩展点机制来扩展RCP的Workbench,依然可以使用SWT(Standard Widget Toolkit), JFace来构建用户界面, 然后再做一点修改,请相信我,确实只需要做一点修改,就可以将RCP应用程序变成一个具有Ajax特性的Web应用程序。以下是RCP应用程序和RAP应用程序的架构对比图,RAP基于Ajax框架qooxdoo 做了一个特殊的SWT实现,目前只实现了SWT的一个子集,叫做RWT(RAP Widget Toolkit), 以此来构建用户再浏览器里面看到的界面,另一边,RAP将OSGi R4核心框架的实现Equinox作为RAP应用程序的服务器端,是的,RAP需要把Equinox嵌入Servlet Container。
图1 —— RCP应用程序和RAP应用程序的架构对比(出自Eclipse网站)
安装RAP
像安装其他Eclipse插件一样, 你可以用Eclipse自带的软件安装界面来安装RAP, RAP的update site是http://download.eclipse.org/technology/rap/update-site ,装完之后,你还需要去RAP的网站http://www.eclipse.org/rap/downloads 下载一个RAP的目标平台,假设你将其下载并解压到c:\rap\eclipse目录,由于RAP和RCP不能同时存在于Eclipse IDE里面,(为什么不能?因为这两者有太多同名的 Java class, RAP的RWT的类名跟RCP的SWT的类名一样), 所以你需要修改Eclipse的目标平台,使其指向RAP目标平台, 点击Window > Preferences... > Plug-in Development > Target Platform, 将Location设置为c:\rap\eclipse,并点击Reload按钮将RAP目标平台的插件加载进来,如图2所示
图2 ——修改Eclipse的目标平台为RAP
好了,到此你把环境准备好了,下面将要介绍如何将RCP程序运行在B/S架构上,正如你猜到的,下面介绍的其实就是如何将一个RCP应用程序转换成RAP应用程序,首先,你需要创建一个RCP应用程序。
创建一个模板RCP应用程序
你可以自己创建一个很简单的Hello World RCP应用程序,也可以复杂一点,比如加一个树控件,弄一些菜单进来。但是我建议用Eclipse自带的RCP模板应用程序,既然Eclipse自带了,而且这样也可以节省不少时间,那为什么不用呢?
点击File->New->Project…, 选择Plug-in Project, 点击Next按钮,为这个将要导入的RCP样本应用程序取名,然后点击Next按钮,在此,将Would you like to create a rich client application设置为Yes,如图3所示,这样在下一页就能看到Eclipse自带的RCP模板应用程序了。
图3——设置Rich Client Application
再次点击Next按钮,选择RCP Mail Template,如图4所示,点击Finish按钮,这样你就得到了一个比较复杂的RCP应用程序了。
图4——选择RCP Mail Template
转换RCP应用程序为RAP应用程序
为了让上面的RCP应用程序运行在B/S架构上,需要将其转换为RAP应用程序。下面分三步修改这个RCP应用程序,使其转换成RAP应用程序。
第一步:修改MANIFEST.MF文件。用Plug-in Manifest Editor打开plugin.xml或者META-INF/MANIFEST.MF文件,切换到Dependencies选项页,在Required Plug-ins列表里面,将里面二个条目org.eclipse.ui和org.eclipse.core.runtime全删掉,增加一个新的条目org.eclipse.rap.ui。插件org.eclipse.rap.ui包含了插件org.eclipse.ui中的绝大多数类和扩展点,而且全名(full qualified name)是一样的。这样可以确保依赖插件org.eclipse.ui的RCP应用程序能够在几乎不做修改的情况下跑在RAP平台中。以下是修改前和修改后的MANIFEST.MF文件,以供对比。
清单1——修改前的MANIFEST.MF文件
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Mail Plug-in
Bundle-SymbolicName: mail; singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: mail.Activator
Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime
Eclipse-LazyStart: true
清单2——修改后的MANIFEST.MF文件
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Mail Plug-in
Bundle-SymbolicName: mail; singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: mail.Activator
Require-Bundle: org.eclipse.rap.ui
Eclipse-LazyStart: true
第二步:修改入口程序。由于RCP应用程序的入口是实现了接口org.eclipse.equinox.app.IApplication的类,在这个RCP模板应用程序里,这个类是mail.Application,为了让Eclipse知道这个类就是RCP应用程序的运行入口点,还需要用如清单3所示的扩展点注册该类。
清单3——RCP应用程序入口注册
<extension
id="application"
point="org.eclipse.core.runtime.applications">
<application>
<run
class="mail.Application">
</run>
</application>
</extension>
RAP应用程序的入口是实现了接口org.eclipse.rwt.lifecycle.IEntryPoint的类,所以你需要将mail.Application修改成如清单4所示的样子,剩下的界面相关的类ApplicationWorkbenchAdvisor,ApplicationWorkbenchWindowAdvisor,Perspective,View都不需要做修改(请注意这里没有包括类ApplicationActionBarAdvisor,后面会对其做一点微小的修改)。
清单4——RAP应用程序入口点
public class Application implements IEntryPoint {
public int createUI() {
Display display = PlatformUI.createDisplay();
return PlatformUI.createAndRunWorkbench( display, new ApplicationWorkbenchAdvisor());
}
}
同时,你需要删除清单3所示的扩展,同样,为了让RAP运行环境知道修改后的mail.Application是RAP应用程序运行入口点,你还需要用如清单5所示的扩展点注册该类
清单5——RAP应用程序入口注册
<extension
point="org.eclipse.rap.ui.entrypoint">
<entrypoint
class="mail.Application"
id="mail.Application"
parameter="rapMail">
</entrypoint>
</extension>
上面的parameter可以为任意值,只要没有被其他的RAP应用程序用过,后面你运行RAP应用程序的时候会用到parameter。
第三步:修改其他有编译错误的地方。剩下还有二个地方出现错误,一个是plugin.xml中的扩展org.eclipse.ui.bindings,这个只是将快捷键绑定到菜单的扩展点,而且目前在RAP中不被支持,你可以将其注释掉或干脆删掉。另外一个是类ApplicationActionBarAdvisor,由于目前RAP目标平台中的的类ActionFactory没有ABOUT成员,为简单起见,直接将makeActions方法中的两条相关语句注释掉,同时,将fillMenuBar方法中的最后一条语句注释掉,清单6是修改后的ApplicationActionBarAdvisor类
清单6——修改后的ApplicationActionBarAdvisor
protected void makeActions(final IWorkbenchWindow window) {
exitAction = ActionFactory.QUIT.create(window);
register(exitAction);
// aboutAction = ActionFactory.ABOUT.create(window);
// register(aboutAction);
newWindowAction = ActionFactory.OPEN_NEW_WINDOW.create(window);
register(newWindowAction);
openViewAction = new OpenViewAction(window, "Open Another Message View", View.ID);
register(openViewAction);
messagePopupAction = new MessagePopupAction("Open Message", window);
register(messagePopupAction);
}
protected void fillMenuBar(IMenuManager menuBar) {
MenuManager fileMenu = new MenuManager("&File", IWorkbenchActionConstants.M_FILE);
MenuManager helpMenu = new MenuManager("&Help", IWorkbenchActionConstants.M_HELP);
menuBar.add(fileMenu);
// Add a group marker indicating where action set menus will appear.
menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
menuBar.add(helpMenu);
// File
fileMenu.add(newWindowAction);
fileMenu.add(new Separator());
fileMen