UML软件工程组织

 

 

Eclipse插件开发如虎添翼
 
作者: 维维   出处: 天极网
 

随着Eclipse作为一个集成开发环境和富客户端(Rich Client)平台而广泛流行起来,更多的公司和个人进入到开发Eclipse插件的队伍中。你想过写一个你自己的Eclipse插件么?这篇文章中我将带领你开发一个简单的可视化插件。这里你可以学习Eclipse插件的体系结构,并且学着熟悉Plug-in Development Environment(PDE)。

简介

许多年以前,当我第一次仔细考察Eclipse时(我记得当时好像是2.0版本),我对它的完全免费印象非常深。它提供了很多非常不错的Java开发能力,但是当时并没有比那些商业版本好上多少。然而,真正吸引我的是我发现可以用我自己的代码随意扩展它的特性。事实上,并不需要特别的工具--Eclipse提供了所有可以用于自身开发的工具和框架。

从那以后,Eclipse开始在各方面成熟起来--它的设计更加改进了,它的结构变得更加强健且不失灵活,它的各种工具也变得更加强大和高效。它已经从一个工具集成框架变成了一个开发胖客户端(rich-client)程序的平台。这也证明了我心目中对它本身的基本设计理念的质量的评价。

扩展Eclipse需要你对可用的结构和工具的基本熟悉和了解。因为学习如何去做一件事情的最好方式就是去试着自己做做看,本篇文章将会帮助你使用插件开发环境PDE开发一个简单的Eclipse插件。当你学习一点Eclipse体系结构的背景信息之后,你将会使用PDE向导来创建一个新的插件,完成一个简单的工作台视图,并且测试你的工作看最后的结果。实现的具体细节不能一一说明了。为了完成这个工作,你需要获得最新的Eclipse SDK(3.1版本),可以从 http://www.eclipse.org/downloads 获得一份免费的拷贝。

所有的东西都是插件

从一个开发者的角度来说,Eclipse是一个开发各种客户端程序的平台。本身其是作为一个开发工具而产生的,现在它的范围已经扩展到包括各种胖客户端应用程序,以及非桌面环境,比如手持设备和嵌入式系统。为了支持如此大范围的应用,高度的可扩展性是非常必要的。每个基于Eclipse的程序都包含了多个组件,它们被称作为插件(plugins),相互间通过预先定义的接口集合进行交互。插件通过一个很小的运行时层来进行管理,负责它们的发现和启动。从3.0版本开始,原来的运行时层实现被新的基于开放服务网关初始化(Open Services Gateway initiative, OSGi)所替代,从而提高了Eclipse向多个硬件和操作系统的移植能力,并且提供了对管理的执行环境的兼容性。因此,目前的Eclipse插件是作为OSGi的组件来开发的。

和其他的组件管理环境类似,每个Eclipse插件的运行时特性是在它的描述符中被指定的,运行时层使用描述符来配置插件的执行环境。在3.0版本以前,描述符是一个XML格式的文件,名为plugin.xml,在每个插件目录的根目录中保存。为了和OSGi运行时整合,插件一般被打包成JAR文件,并且它们的属性比如单一的标识符,版本号,运行时classpath和导出的包,被包含在它们的JAR manifest中(即META-INF/MANIFEST.MF)。然而,对于一般记录Eclipse插件的特性的描述符--插件扩展和扩展点--仍然留在plugin.xml文件中描述。

一个插件的扩展点基本上是它的组件配置点,使用XML Schema子集描述。一个完成某种抽象功能的插件,比如在工作台显示独立视图等,将会公布一个扩展点,指定每个实现必须完成什么才能被这个插件使用。这些一般需要包含简单的属性,比如窗口标题和图标路径,同时也包含实现具体接口的类名称。在这里的例子中,每个要提供一个视图实现的插件必须声明一个插件描述符属性的ID是org.eclipse.ui.views扩展点的扩展。这个扩展必须指定类实现接口的名为org.eclipse.ui.IViewPart。在运行时,工作台插件查找插件记录中所有的org.eclipse.ui.views的扩展并且将它们提供给用户作为可显示的视图。当用户选择打开某个视图时,工作台插件初始化指定在插件描述符中视图的实现类,并且通过接口org.eclipse.ui.IViewPart来和它交互。这个机制是Eclipse扩展性的基石。插件给其他的插件提供具体的实现,很多都是实现了自身高度抽象,并且将它们作为扩展点提供给其他的插件来完成。

Listing 1: plugin.xml的内容:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
 <plugin>
  <extension point="org.eclipse.ui.views">
   <category id="com.developer.superview.category1" name="Developer.com"/>
   <view category="com.developer.superview.category1" class="com.developer.superview.Superview" id="com.developer.superview.view1" name="Superview"/>
  </extension>
 </plugin>

插件开发环境

就像你所看到的一样,开发Eclipse程序的核心任务主要包含创建实现一个或者多个扩展的插件。理论上来说,没有东西会阻止你使用记事本,或者vi或者命令行中的javac来开发Eclipse插件(我想听听尝试过的人怎么说得!)。幸运的是,Eclipse拥有一个强大的工具集来使这一任务变得简单。插件开发环境PDE是作为Eclipse SDK的一个部分自由分发的,并且作为一个基于Eclipse的IDE工具的好范例而存在--它只是一些插件和它们的扩展的集合(事实上他们也留下了一些扩展点,你可以用这些扩展点来开发自己的PDE扩展)。

在PDE中,每个正在开发的插件都是被单个的Java工程所代表。插件工程具有一些独一无二的特性来标示自己。比如说它们每一个都有一个插件描述符(一个manifest和/或一个plugin.xml文件),一个基于描述符指定的依赖关系的动态classpath,特殊的编译器,和其他配置属性。PDE提供了一个插件创建向导,可以选择各种需要的部分创建插件工程。

PDE带有一个特别的多页编辑器来使得插件开发更加简单。插件Manifest编辑器用到3个文件--包含的manifest(META-INF/MANIFEST.MF),plugin.xml和build.properties.它允许你编辑所有必要的属性来描述一个插件--它的基本运行时要求,依赖,扩展,扩展点等等。当开发插件的时候你需要做更详细的了解。

因为Eclipse插件都是Java的工程,它们缺省都是逐步构建的,不需要特别的人工编译步骤。PDE也允许使用Ant来创建非自动编译的插件;你可以为你的插件创建一个Ant的build脚本(在Package Explorer中,右键点击你的plugin.xml并且选择PDE Tools -> Create Ant Build File),它提供了创建多个目标输出的方式(比如插件JAR包,源代码包等等)。

为了测试你的工作,PDE提供了一个特别的启动配置类型,允许你使用它的配置中包含的工作区插件来启动另外一个工作台实例(被称为运行时工作台)(也被称作为self-hosting--你不比将你的插件安装进一个外部的工作台来测试它们,你可以使用自己的开发工作台动态安装)。你的Eclipse启动配置将允许你指定你想包含的哪个插件,特殊的命令行参数,环境属性等等。

PDE也有一个强大的用户文档和扩展参考信息(Javadoc和扩展点文档)。因为它是和Eclipse在一个规则下分发的,所以它的代码也是完全开放的,并且缺省包含的SDK中。
创建简单的插件

为了对使用PDE开发插件有个更好的理解,你可以开发一个简单的工作台视图。它的功能是列出运行时工作台中所有的可用视图(你可以称它为超级视图)。当你这样做的时候,你可以使用这个身边的例子,检查插件Manifest编辑器的各个部分。

首先,启动你的Eclipse SDK,选择一个空工作区。当你关掉欢迎页面时,你应该缺省进入Java开发模式。第一步,使用新建插件向导来创建插件。然后,使用插件Manifest编辑器编辑其描述符,并且使用JDT来实现一个Java类。最后,在一个运行时工作台启动插件来看效果。好,开始:

1. 在main menu中,点击File->New->Project,然后选择Plug-in Project并且点击Next;

2. 在下一个向导页中,输入com.developer.superview作为工程名。点击Next;

3. 在此页中,保持所有的域为缺省值,点击Finish。当被问到是否转换到插件开发模式时,选择yes。这时,插件已经被创建了,并且你可以在插件Manifest编辑器中看到总览。

总览页面包含了一些一般属性,如插件的ID,版本,名称,提供者,插件类和平台过滤器。它还提供了到其他页面的链接,这些页面指定了插件内容,编译配置,和测试运行的链接以及导出插件(所有的和简单描述)。ID是必须的且必须为独一无二的。版本一般为3到4个部分组成,使用点号隔开的版本标识符(major.minor.service{.qualifier})。插件版本在你的平台插件开发向导中有详细记述。在这个练习里,你可以指定为缺省的1.0.0。姓名和提供者是科学院的,至是被用来在产品配置里显示的标记。类属性也是可选的,目前它可以被用来代表一个单独的运行时插件实例,可以用来作为一个单独的对多个插件特定数据的访问点。在这个例子里,向导闯将了一个缺省的类实现,你可以在例子的任何代码里提到它。平台过滤器可以用来限制插件的平台可用性(这个例子里没有用到)。


 依赖页面允许你指定其他一些你所依赖的插件,无论是编译的还是运行时的。增加一个插件依赖意味着被选择插件的所有Java包的导出,包含任何的扩展点,对你自己的代码都是可用的。你可以选择在你的SDK安装时增加任何可用插件,包括你的工作台(也就是说,其他你当前正在使用的插件)。

在我们这里例子里,你将把org.eclipse.core.runtime和org.eclipse.ui作为你的依赖。任何依赖都是可选的(确认你的代码需要它),你可以选择重新导入一个依赖(选择列表中的一个插件,并且点击属性…)。你可以请求某个Java包对你的类启动器可用,无论它是从何而来。这是一个高级开发主题在你的平台文档中有详细叙述。这个页面里,你可以做一些各种类型的依赖关系的分析,可以给你一个更加好的插件依赖的认识。 运行时页面允许你指定想导出的Java包(也就是说,在你的插件列表中使你的插件可见)。在这个列表中,你无须导出任何东西,因为你不提供任何的功能作为公共API可用。如果你要这么作,拿你必须使得它们针对其衍生的插件可用(这是更加高级的开发主题了)。Classpath节是用来指定哪个类文件夹或者JAR文件应该作为你的运行时classpath,如果有多个的话(缺省只有你的插件的根目录是被包含在它的classpath里)。

扩展页面是你指定你所有的插件扩展的地方。它包含了一个通过你插件实现的扩展的树(你可以从列在你的依赖的插件中选择公布的扩展点),和一个详细的包含反映你的当前树选择的域的表单。要创建新的扩展元素,右键点击树中的元素,选择New子菜单。对元素的选择以及每个元素的属性集合,依赖于关联的扩展点。你可以通过右键点击树中的扩展的方式来获得你的扩展点文档,然后选择Show Description。事实上,为了继续我们的例子,我们将为超级视图实现增加一个新的扩展:

4. 点击Add。在New Extension对话框中,选择扩展点org.eclipse.ui.views。点击Finish。

5. 右键点击列表中的扩展;选择New->category。输入Developer.com作为名称。

6. 右键点击扩展,选择New->view,输入SuperView作为名称,com.developer.superview.category1作为分类(和在上一不中创建的类型ID匹配)。

7. 点击class链接。输入Superview作为类名,点击Finish。这将会创建一个新的实现所需接口的类,并且在Java编辑器中打开它。

你可以马上回到视图的开发中来。现在,激活插件Manifest编辑器,点击扩展点的Tab。如果可用,将会列出所有你的插件公布的扩展点。每个扩展点的细节都是可以使用扩展点方案编辑器来编辑的(这里不再详细叙述了)。

生成页面允许你对插件的生成配置进行指定(或者选择自定义生成来生成一个完整的自定义的生成过程,这个你需要自己实现)。这些信息将会被增量生成器(你的工程的生成路径也会相应的更新,这也是你不能直接更改而让PDE来为你做的原因)和一个Ant生成脚本所使用,你只能选择两者中的一个。在这个联系里,你无须特别的生成要求。若你要这样作,比如为你的视图使用一个自定制的图标,你必须保证它的目录是在二进制生成段中被检查过的,以使得它对你的代码在运行时可用。

MANIFEST.MF,plugin.xml,和build.properties允许你编辑相应文件的源代码。这个只对高级熟练的Eclipse开发者推荐使用。

现在你对插件Manifest编辑器比较熟悉了,我们可以继续我们的例子:

8. 激活Superview.java编辑器。你可以看到,为了完成视图的实现,你必须实现最少两个方法:createPartControl(Composite)和setFocus()。这里,我就不详细讨论底层的API了。现在,你应该知道你要创建一个表式的可视化组件--表格查看器--来显示你的视图内容。你将配置它为一个内容提供者来给它操纵你的组件的能力(具体的说就是提取出你的模型结构元素来适应表格的包含),和一个标志提供者,来给予它使用适当的标志和可选图片来转化你的模型元素到表格项的能力。你也可以给它配置一个排序器来按照字母表顺序显示表项。最后,你给它一个输入--你的模型对象,即运行时可用的一组所有可用视图的描述符。完整实现如下:

Listing 2: Initial view implementation:

public class Superview extends ViewPart
{
 private TableViewer viewer;
 public void createPartControl(Composite parent)
 {
  viewer = new TableViewer(parent);
  viewer.setContentProvider(new ArrayContentProvider());
  viewer.setLabelProvider(new LabelProvider());
  viewer.setSorter(new ViewerSorter());
  viewer.setInput(PlatformUI.getWorkbench().getViewRegistry().getViews());
 }
 public void setFocus()
 {
  viewer.getTable().setFocus();
 }
}

这已经足够运行这个例子了,保存,然后:

9. 在你的Package Explore里右键点击,选择Run As -> Eclipse Application。这将创建一个新的Eclipse使用缺省值的启动配置,启动它。

10. 当运行时工作台出现的时候,你应该看到欢迎视图。点击Window->Show View->Other…选择Developer.com->Superview。点击OK。

你应该看到的是Superview显示的形式是:视图<视图号>。这作为一个例子来演示PDE使用已经足够了。然而,如果你想更深一步进入JFace的学习,你可以学着看能否把这个界面做的更加人性化一点。

在这里,表格里每条记录代表一个工作台视图;你提供的模型对象作为该查看器的输入为一组视图的描述符(IViewDescriptor),你使用的内容提供者将任何数组对象转化为一个它的元素列表(父子关系)。但是,标志提供者只是简单的使用了每个元素的toString()方法来作为其标记。接口IViewDescriptor提供方法来获得视图标号(getLabel()),甚至可以获得视图的图标图像(getImageDescriptor())。你所要做的是重载两个标记提供者的方法:

 11. 关闭运行时工作台。在Superview.java编辑器中,子类new LabelProvider()如列表3所示:

Listing 3: Label provider customization:

viewer.setLabelProvider(new LabelProvider()
{
 private final Map images = new HashMap();
 public String getText(Object element)
 {
  return ((IViewDescriptor) element).getLabel();
 }
 public Image getImage(Object element)
 {
  Image image = (Image) images.get(element);
  if (image == null)
  {
   IViewDescriptor view = (IViewDescriptor) element;
   ImageDescriptor desc = view.getImageDescriptor();
   image = desc.createImage();
   images.put(element, image);
  }
  return image;
 }
 public void dispose()
 {
  for (Iterator i = images.values().iterator(); i.hasNext();) ((Image) i.next()).dispose(); super.dispose();
 }
});

这里,你已经重载了getText(Object)方法来返回元素(一个IViewDescriptor的实例)的标号。为了使得看起来更加好看,你可以重载getImage(Object)方法来返回每个视图的文字标号的关联图标。这里比较复杂一点了,你必须学习JFace和SWT,你将会发现图像(org.eclipse.swt.graphics.Image)是操作系统额资源,必须被程序来管理。然而,IViewDescriptor只是返回了一个ImageDescriptor而不是图像本身。一个图像标识符可能被用来创建一个Image实例,但是必须能够在不需要的时候释放。由于这个原因,你必须跟踪创建的所有的Image实例并在不需要的时候释放掉它。

要看最后的输入,重新启动运行时工作台。(Ctrl + F11)


 打包并且分发插件

即使你可能完成了插件的开发和测试,你也需要将其从开发环境里导出分发到用户手中。幸运的是,Eclipse没有把这个交给你自己完成。你可以使用导出向导,它出现在你的插件编辑器的总览页面里。它将创建一个分发包文件,包含你的插件代码和资源。用户只要将其解压在他们的Eclipse安装里,如果它们的环境的所有依赖关系都满足,那么Eclipse将会在需要时自动发现和激活你的插件。

这种形式的分发和安装被成为未管理的--如果你将来进行更新的话,你将发现和安装你的插件的更新的任务交给了用户。一个更加有组织的方法时将你的插件组织成feature。feature是一组同时安装和管理的插件。在集合插件之外,feature包含了一些信息,这些信息允许Eclipse更新管理器来定位公布的更新,并且发现新的关联的feature。这样的发布在某个web目录下的更新叫做更新站点。PDE提供了向导和编辑器来支持feature和更新站点的开发。

如果你开发整个应用程序而不止是插件和feature,需要已有的基于Eclipse的产品的安装,你需要使用产品配置编辑器(Product Configuration editor)和产品导出向导(Eclipse Product export wizard),把你的应用作为一个独立的Eclipse产品。这个高级主题可以独立成为一篇文章了。

结论

Eclipse是一个伟大的工具和胖客户端应用平台,不单提供了它的免费开放组件,页提供了它自身的开放实现。在Eclipse中,所有功能都封装成插件,它们一个个使用良定义的扩展点结合在一起。它的PDE提供了功能强大的工具和向导来帮助你开发你自己的插件。更重要的是,它提供了整个环节的开发支持,包括分发和后期产品维护。


 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号