Eclipse插件开发-如何扩展WTPWizard

简介:Eclipse 最有魅力的地方就是它的插件体系结构,在Eclipse中实现的绝大部分功能是由相应的 插件完成的。本文介绍了Eclipse WTP Wizard插件开发,它源于实际应用中开发IBM WebSphere Multichannel Bank Transformation Toolkit(BTT)的创建应用程序向导 (New Application Wizard)。 文章首先概要介绍Wizard;然后详细分析JFace Wizard,WTP Wizard 设计模式,包括需要使用的接口和 函数。最后以一个实例的形式引导读者深入理解WTP Wizard扩展方法。

引言

众所周知 Eclipse 是一个成熟的、精心设计的以及可扩展的体系结构。Eclipse 中除了小型的运行时 内核之外,其余所有功能模块都是插件。其中 Web Tools Platform. (WTP) 就是在 Eclipse 平台上扩展 的,用来开发 J2EE Web 应用程序的插件集合。既然 WTP 是插件,那么为什么还需要针对它进行扩展呢 ? WTP 提供了丰富的功能,比如源码编辑器、图形编辑、J2EE 项目构建和 J2EE 向导 WEB 服务以及数 据库操作等,由于业务需求,需要编辑特定语法格式的文档,如进行语法高亮显示、校验、编辑助手 (Code Assist)等,这时就需要对 WTP 进行扩展。总之,当 WTP 提供的通用功能需要定制,或者不符 合业务需求时,需要进行 WTP 扩展开发。

向导(Wizard)是一种交互式的帮助实用程序,向导通过多步操作中的每一步引导用户,提供有用的 帮助信息,并在这一过程中解释选项功能,最终引导用户完成特定任务。向导在 Eclipse 中随处可见, 选择 File > New > Project, 对话框所列每一项都是一个独立的功能向导。

图 1. Eclipse 向导

WEB Tools Platform(WTP)作为一个基于 Eclipse 开发 J2EE WEB 应用程序的工具集,它提供了创 建 J2EE 工程向导、创建 WEB 服务向导、创建 J2EE Servlet 向导以及导入导出 J2EE 工程向导等。下 图示例了 WTP 的一些常用向导:

图 2. Java EE project creation wizards(1)

图 3. Java EE project creation wizards(2)

图 4. Java EE components import and export wizards(1)

图 5. Java EE components import and export wizards(2)

图 6. Web and EJB artifacts wizards(1)

图 7. Web and EJB artifacts wizards(2)

 

Eclipse 向导设计模式

在 Eclipse 中,向导装载一系列向导页面(WizardPage),构造出一个复杂的界面,装载领域类来处 理具体业务逻辑,维护向导页面之间以及领域类之间的数据传递和状态共享。向导必须具备一个完成操作 (Finish Operation)。其中的 WizardPage 是一些 SWT/JFace Widget 容器,他们之间按照业务规则存 在跳转关系。

为了便于理解,我们从 JFace Wizard 开始,下图是 JFace Wizard 原理图,它的数据存在于 Page 中,相当于 View-Control 方式,没有统一的数据模型(Model),因此它适合于做简单页面跳转向导。

图 8. JFace Wizard

数据模型向导(Data Model Wizard)扩展于 JFace Wizard,其内嵌一个数据模型(Data Model), 通过使用 Synchronize Helper 完成页面控件(Page widget)与 Data Model 数据之间的同步。

Data Model 很像是一个数据(属性)集合,每一个属性(Property)是一个键值对(key-value), 可以注册一些属性监听器(Listener)来监视属性值变化。Data Model 中用 Property 来记录功能构件 的状态,并提供了访问和修改 Property 的接口。这些接口中大部分都是提供给后台的 MVC 机制使用, 例如 View 对 Property 的访问和修改,以及 Operation 在执行动作时对 Property 的访问等。用户可 以在这些访问和修改的接口中定义 Property 访问和修改规则,例如在访问 Property 的接口中,根据特 定的条件返回不同的 Property 值。用户还可以在 Data Model 中定义自己的 Property,并通过 Data Model 提供的接口对自定义的 Property 进行初始化(Init)和验证(Validate)。

用户也可以自己访问和修改 Data Model,Data Model 为用户提供了统一的方法,getProperty() 和 setProperty()。

Data Model 提供了用户收集数据的智能途径;简化了 Wizard Operation 执行并为实现和扩展 Wizard 提供了便利。下图为 Data Model 类图。

图 9. Data Model

Data Model Wizard 使用 DataModel-View-Operation 模式,该模式在 Eclipse 的插件开发中经常用 到 , 被用来实现一个特定的功能构件。它的基本原理是:DataModel 用来封装功能构件的一组状态; View 用来与用户进行交互,它将用户需要的状态显示出来,并提供用户的输入接口;Operation 负责根 据状态执行特定的动作。Data Model Wizard 完整类图如下所示:

图 10. Data Model Wizard

WTP 向导设计模式

WTP Wizard 是 Data Model Wizard 的一个扩展应用,它在 Data Model Wizard 的 DataModel-View -Operation 模式基础上,添加了一个新的单元 DataModeProvider,形成 DataModel- DataModelProvider-View-Opration 模式。DataModeProvider 的出现削弱了 Data Model 的能力,使得 后者完全变成一个单纯 Property 的集合,而不再具有任何的额外功能,例如 Property 初始化,验证, 可定义的访问和设置等。Data Model 对用户完全是一个黑盒。用户如果想要访问 Data Model 或者为 Data Model 定义特定的规则,需要通过 DataModelProvider 来实现。DataModelProvider 接管了 DataModel – View-Opration 中 Data Mode 除缓存 Propety 外其余的所有功能(包括初始化,验证, 可定义的访问和设置等)。下图显示了 DataModel – DataModelProvider – View-Opration 的基本原 理。

图 11. DataModel-DataModelProvider-View-Operation

在 DataModel-DataModelProvider-View-Operation 中,Data Model 不具有语义信息,它已经退化为 一个单纯的键值对的集合,而键值的语义由 DataModelProvider 附加上去。用户在 DataModelProvider 中定义 Property 的名称,DataModelProvider 将会根据这些 Property 的定义在 DataModel 中自动创 建键值对。因此无论是访问还是修改特定的 Property,都需要通过 DataModelProvider。

典型的访问 Property 方法的代码片断如下:

IDataModel dataModel = DataModelFacTory.createDataModel(new DataModelProvider ());   dataModel.getProperty(IDataModelProperties.PROPERTY_NAME);   dataModel.setProperty(IDataModelProperties.PROPERTY_NAME, property);

与 DataModel-View-Opration 相比 DataModel-DataModelProvider-View-Opration 具有如下特点:

Data Model 可以专心存储数据,而不需要考虑与其它单元的交互。因此在形式上更为统一。而事实上 ,在 WTP 中,Data Model 就仅包含了 DataModel 和 DataModelImp 两种形式。

将 Data Model 进一步解耦,使得状态的保存和存取功能分开。有利于对存取功能的进一步扩展。

WTP 向导扩展实例

动态 WEB 应用向导 (Dynamic Web Application Project Wizard) 能够创建出 J2EE 规范的 Web 应用程序,但有时候需要创建订制过的 (Customized) WEB 应用程序,例如创建 Portlet 应用程序,必 须要创建 Portlet 描述文件。

我们通过创建一个 New Project Wizard,该 Wizard 具备部分 Dynamic WEB Application Project Wizard 特征,同时能够创建 Portlet 部署描述文件。

New Project Wizard 界面如图所示:

图 12. 扩展实例主界面

首页中新增 Main Class Group Panel,方便用户输入新建的 package 名称和主程序入口文件名称。

1. 创建 Plug-in Project 并注册 Wizard 扩展点,插件清单文件 plugin.xml 如下所示:

清单 1. 插件扩展描述文件

                           Create a WTP Sample Project              

org.eclipse.ui.newWizards 扩展点,是“新建向导”扩展点;category 定义的是对这个扩展点的归 类;wizard 标记是 org.eclipse.ui.newWizards 扩展点自定义的格式,name 属性定义的是显示的名称 ,category 属性代表此向导的分类。class 属性表示此扩展点对应的实现类,大部分扩展点都需要编写 实现代码,因此需要这个属性来指定此扩展点使用的是哪个类;接下来详细介绍如何实现该 Wizard class。

2. 创建 WTP Wizard 所需要的类

根据前面分析,WTP Wizard 所采用的 DataModel-DataModelProvider-View-Operation 设计模式涉及 以下四个实体类:

DataModelWizard   DataModelWizardPage   AbstractDataModelProvider   AbstractDataModelOperation 

清单 2. Wizard

public class SampleProjectWizard extends DataModelWizard implements  INewWizard  {  public SampleProjectWizard(IDataModel model) {   super(model);   setWindowTitle("My Wizard Titile");  }  public SampleProjectWizard() {   super();   setWindowTitle("My Wizard Titile");  }  protected void doAddPages() {   addPage(new SampleProjectFirstPage(getDataModel(), "first.page"));  }  protected IDataModelProvider getDefaultProvider() {   return new SampleProjectCreationDataModelProvider();  }  public void init(IWorkbench arg0, IStructuredSelection arg1) {   // do nothing  }  }

为了简化 Sample 理解复杂度,doAddPages 方法中只加入首页(SampleProjectFirstPage),而忽略 了其他页面。在构造函数中,使用 SetWindowTitle 方法设置 Wizard 标题。getDefalutProvider 中注 册 SampleProjectCreationDataModelProvider 用来执行控制操作。

清单 3. Wizard Page

protected void createPresetPanel(Composite top)  {  final Group group = new Group(top, SWT.NONE);  group.setText("Sample Main Class");  group.setLayoutData(gdhfill());  group.setLayout(new GridLayout(2, false));  Label lp = new Label(group, SWT.NULL);  lp.setText("Package");  Text tp = new Text(group, SWT.BORDER);  tp.setLayoutData(gdhfill());  Label lc = new Label(group, SWT.NULL);  lc.setText("Name");  Text tc = new Text(group, SWT.BORDER);  tc.setLayoutData(gdhfill());  synchHelper.synchText(tp,    SampleProjectCreationDataModelProvider.PACKAGE, null);  synchHelper.synchText(tc,    SampleProjectCreationDataModelProvider.MAIN_CLASS_NAME, null);  }

Sample Wizard 的首页隐蔽了 Dynamic Web Project Wizard 首页中 Dynamic WEB Module Version 与 Configuration Group。因此 Sample Page 通过继承 WEB Project Page,并重写相关 createPresetPanel,createPrimaryFacetComposite 方法来达到目的。

这里通过 synchHelper 方法的 synchText 方法实现 Text 空间与 provider 想关联的 Model 同步, 当 Text 值发生改变时,helper 通过自身 Listener 机制通知 Model 来同步 UI 数据。相应地, synchHelper 还提供了与 Label、Combo/ Tree ,CheckBox 等 Widget 同步方法。

清单 4. Provider

public class SampleProjectCreationDataModelProvider extends   WebFacetProjectCreationDataModelProvider  {    public static final String PACKAGE = "MAIN_CLASS_PACKAGE";    public static final String MAIN_CLASS_NAME = "MAIN_CLASS_NAME";    public static final String DEFAULT_PACKAGE = "com.sample.app";    public static final String DEFAULT_MAIN_CLASS_NAME =  "NewsListSample";  public Object getDefaultProperty(String propertyName) {   if (PACKAGE.equals(propertyName))   return DEFAULT_PACKAGE;   if (MAIN_CLASS_NAME.equals(propertyName))   return DEFAULT_MAIN_CLASS_NAME;   return super.getDefaultProperty(propertyName);  }  public Set getPropertyNames() {   Set propertyNames = super.getPropertyNames();   propertyNames.add(PACKAGE);   propertyNames.add(MAIN_CLASS_NAME);   return propertyNames;  }  public IStatus validate(String propertyName) {   //do validate   return super.validate(propertyName);  }  public IDataModelOperation getDefaultOperation() {   return new SampleCreationOperation(getDataModel());  }  }

如前图所示,Page 中新增了两个字段 Main Class Package 和 Main Class Name,所以 Provider 继 承 WebFacetProjectCreationDataModelProvider 之后重写 getPropertyNames 方法,加入上述字段。为 了方便用户使用 wizard, 重写 Provider 中 getDefaultProperty 方法,为 Package 和 Class Name 提 供默认值。Data Model Wizard 作为一套完善的 MVC 框架,实现了 Model 检验功能,当 UI 输入值发生 改变时会触发 validate 方法,并将检验结果显示在 Wizard 的 Title 区域。

清单 5. Operation

public IStatus execute(IProgressMoniTor moniTor, IAdaptable info)   throws ExecutionException  {  IStatus status = super.execute(moniTor, info);  if (OK_STATUS == status) {   try {   // copy default resource file   ResourceUtil.copyFiles(project.getProject(), moniTor);   String spackage = getDataModel().getStringProperty(   SampleProjectCreationDataModelProvider.PACKAGE);   String sname = getDataModel().getStringProperty(           SampleProjectCreationDataModelProvider.MAIN_CLASS_NAME);   // You can use package and class name to create the main   // class here   } catch (Exception e) {   e.printStackTrace();  }  return status;  }

上一小节通过 Provider 的 getDefaultOperation 告诉 DataModelWizard,当 Wizard 完成的时候所 执行的具体操作。这里只需重写父类的 execute 方法,当父类 execute 执行完毕后,可以执行额外的创 建工作。

总结

上述扩展 WTP Wizard 方式可以归纳为使用面向对象技术扩展已有 Wizard :扩展 Data Model Wizard 的子类,注册一个新的 Wizard,该新 Wizard 可以使用重写、覆盖等技术改变已有 Wizard 特性 。事实上还有另外一种扩展已有 Wizard 的方式 —— 通过扩展点扩展。该扩展方式将会影响到所有被扩 展的实例,且只能增强被扩展 Wizard,不能隐蔽或者减少已有 Wizard 的功能,读者可以自行查阅相关 文档。

感受最美的风景。你曾经说,

Eclipse插件开发-如何扩展WTPWizard

相关文章:

你感兴趣的文章:

标签云: