第一个Eclipse插件

在Eclipse中使用PDE(Plugin Development Environment)进行插件开发。在PDE中为大家准备了几个模板供大家参考。第一步咱们先利用模板制作一个简单的插件作为和PDE的第一次接触。

1.生成插件工程

通过选择[文件]->[新建]->[工程...]启动[新工程(New Project)]向导。在插件开发的时候我们就不能选择通常的java工程了,要选择新建一个插件工程。

选择[插件工程(Plug-in Project)]后点击[下一步(Next)]。下一步,输入一个适当的项目名(图2)。习惯上项目名和插件的ID是相同的。插件ID和java包的命名方式相同,必须一个世界范围唯一的名称。在这里用cn.sf.amateras.sample作为项目名称(=插件ID)。点击[下一步(Next)]。

图1 生成插件工程

图2 输入插件信息 输入[插件ID]、[插件版本]、[插件属性]、[图3] 等信息。[插件ID]会被自动设成之前输入的[工程名]。没有其他特别的设定的话继续点击[下一步(Next)]。

图3 输入生成工程必要的信息

图4 模板选择

图5 输入模板信息

根据选择的模板生成的插件在(图5)的画面可以修改一些信息。如果没有特别需要设定的地方点击[完成(Finish)],生成工程。

PDE透视图

插件工程生成后,就会切换到PDE(插件开发)透视图。工程此时根据选择的[Hello,World]模板生成了插件的源代码,并且打开了manifest编辑器。

图6 PDE(插件开发)透视图

2. 插件的动作

接下来我们看一下插件的动作。manifest编辑器的[概要]页面右侧[启动Eclipse应用(Luanch an Eclipse application)]。点击后,会启用一个新的Eclipse实例。这个新的实例被称为[运行时工作台]。运行工作台可以以嵌入当前正在开发的插件的状态启动,以使开发者可以对插件的动作进行确认。

图7 启动运行时工作台

启动的运行时工作台,会在菜单栏上增加一个新的菜单项。这个菜单项就是插件的代码追加上去的。在工具栏上也增加了一个相应的按钮。

工具栏上的按钮和菜单项目效果相同,都会出现一个[Hello,Eclipse World]的对话框。

Eclipse版的Hello World就完成了。确认完这些动作后,就可以关闭当前的运行时工作台了,咱们在下个小节的讲解中还要去参考插件工程的代码呢~

图8 示例中新增的菜单项和工具栏按钮以及相应的动作

MANIFEST.MF和plugin.xml

一个插件包含MANIFEST.MF和plugin.xml两个配置文件。MANIFEST.MF是OSGi的handler配置文件,记录了插件ID、名称、作者、和其他插件的依赖关系等。plugin.xml记录了插件的扩展和扩展点的定义等信息。

Eclipse3.1以前由于还没有采用OSGi技术,插件的所有信息都记录在plugin.xml里。所以应用在Eclipse3.1以前版本的插件如果要应用于Eclipse3.1和以后版本时要注意遵守OSGi的配置文件定义规范。

3. PDE的功能

PDE(插件开发环境·Plugin Development Enviromment)提供了插件开发的各种功能。因为插件的开发使用java语言,所以也会使用到java编码工具JDT。

Manifest编辑器 PDE提供的功能中最重要的就是Manifest编辑器。编辑器可以为插件的两个配置文件提供图形化的编辑功能。(图9) 编辑器的配置项目非常多,可以通过编辑器下面的tab页切换设定画面。

图9 Manifest编辑器

Manifest编辑器各tab页

页面
说明

Overview

可以设定插件的概要信息。生成用于发布的文档以及启动运行时工作台。

Dependencies

设定插件间的依赖关系。

Runtime

可以设置导出包和ClassPath。

Extensions

管理当前插件对扩展点的扩展。

Extension Points

管理当前插件的扩展点。

Build

生成工程时的各种设定。

MANIFEST.MF

显示MANIFEST.MF的源代码。

plugin.xml

显示plugin.xml的源代码。

build.properties

显示build.properties的源代码。

在Overview以外的tab页上部会显示一些快捷键按钮,使用这些按钮也可以进行启动运行时工作台,导出等操作。

图10 编辑器上部

下面介绍一下PDE题供的几种视图。在[Window]->[Show View]中可以找到没有被显示的视图。

[插件(Plug-ins)]视图 所有的插件列表,包含当前工作区内正在开发的插件。打开插件节点可以显示插件下包含的资源,但是以jar包提供出来的插件就显示不出来了。 在插件节点上点击右键选择[打开依赖关系(Open Dependencies)]可以打开后面要介绍的[依赖关系]视图,表现插件间的依赖关系。右键菜单中也可以把选中的插件作为一个工程引入到当前工作区内。

[依赖关系(Plug-in Dependencies)]视图 表现了插件间的依赖关系。可以分别表示当前插件依赖的插件和依赖当前插件的插件。

[插件注册(Plug-in Registry)]视图 当前工作台加载的所有插件列表。打开插件节点,显示插件提供的扩展和扩展点、依赖关系等。

[错误Log(Error Log)]视图 错误Log视图虽然不是PDE提供的功能,但是在插件开发的时候非常有用。它可以表现当前工作台内发生的错误,并且在错误上双击既可以导向到错误发生的地方。

Plugin-in Selection Spy 同时按下alt+shift+F1 Plugin-in Selection Spy是从Eclipse3.4开始加入的新功能,能够显示当前焦点所在的编辑器、视图、向导、对话框等的内部信息。把已有的插件作为参考,进行插件开发,使用这个功能是再合适不过了。

4. 解读示例插件的代码

让我们回到插件工程来,看一看插件工程生成的代码。首先看一下plugin.xml的代码。

plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.ui.actionSets"> ①
      <actionSet
            label="Sample Action Set"
            visible="true"
            id="cn.sf.amateras.sample.actionSet">
         <menu
               label="Sample &Menu"
               id="sampleMenu">
            <separator
                  name="sampleGroup">
            </separator>
         </menu>
         <action
               label="&Sample Action"
               icon="icons/sample.gif"
               class="cn.sf.amateras.sample.actions.SampleAction" ②
               tooltip="Hello, Eclipse world"
               menubarPath="sampleMenu/sampleGroup"
               toolbarPath="sampleGroup"
               id="cn.sf.amateras.sample.actions.SampleAction">
         </action>
      </actionSet>
   </extension>
</plugin>

为了在菜单栏增加一个项目,文件中使用了extension元素。 ①的id指定了扩展点的名称org.eclipse.ui.actionSets。extension里的内容根据扩展点而不同。示例插件中包含了actionSet、menu、action等元素。 ②中的class属性指定了cn.sf.amateras.sample.actions.SampleAction类作为响应菜单或者工具栏按钮的action类。

SampleAction.java

package cn.sf.amateras.sample.actions;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.jface.dialogs.MessageDialog;

/**
 * Our sample action implements workbench action delegate.
 * The action proxy will be created by the workbench and
 * shown in the UI. When the user tries to use the action,
 * this delegate will be created and execution will be 
 * delegated to it.
 * @see IWorkbenchWindowActionDelegate
 */
public class SampleAction implements IWorkbenchWindowActionDelegate {
    private IWorkbenchWindow window;
    /**
     * The constructor.
     */
    public SampleAction() {
    }

    /**
     * The action has been activated. The argument of the
     * method represents the 'real' action sitting
     * in the workbench UI.
     * @see IWorkbenchWindowActionDelegate#run
     */
    public void run(IAction action) {   //......①
        MessageDialog.openInformation(
            window.getShell(),
            "Sample",
            "Hello, Eclipse world");
    }

    /**
     * Selection in the workbench has been changed. We 
     * can change the state of the 'real' action here
     * if we want, but this can only happen after 
     * the delegate has been created.
     * @see IWorkbenchWindowActionDelegate#selectionChanged
     */
    public void selectionChanged(IAction action, ISelection selection) {
    }

    /**
     * We can use this method to dispose of any system
     * resources we previously allocated.
     * @see IWorkbenchWindowActionDelegate#dispose
     */
    public void dispose() {
    }

    /**
     * We will cache window object in order to
     * be able to provide parent shell for the message dialog.
     * @see IWorkbenchWindowActionDelegate#init
     */
    public void init(IWorkbenchWindow window) {
        this.window = window;
    }
}

①run()方法内记录了action执行时的处理。利用MessageDialog.openInformation方法打开了一个对话框。

咱们再看看生成的另外一个类--Activator类。这个类对插件的生命周期进行了管理,被称为插件类。

Activator.java

package cn.sf.amateras.sample;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;  //....①
import org.osgi.framework.BundleContext;

/**
 * The activator class controls the plug-in life cycle
 */
public class Activator extends AbstractUIPlugin {

    // The plug-in ID
    public static final String PLUGIN_ID = "cn.sf.amateras.sample"; //$NON-NLS-1$

    // The shared instance
    private static Activator plugin;

    /**
     * The constructor
     */
    public Activator() {
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
     */
    public void start(BundleContext context) throws Exception {//....③
        super.start(context);
        plugin = this;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) throws Exception {//....④
        plugin = null;
        super.stop(context);
    }

    /**
     * Returns the shared instance
     *
     * @return the shared instance
     */
    public static Activator getDefault() {//....②
        return plugin;
    }

    /**
     * Returns an image descriptor for the image file at the given
     * plug-in relative path
     *
     * @param path the path
     * @return the image descriptor
     */
    public static ImageDescriptor getImageDescriptor(String path) {
        return imageDescriptorFromPlugin(PLUGIN_ID, path);
    }
}

示例中的插件类继承自AbstractUIPlugin(①)。如果没有UI的插件继承AbstractUIPlugin的父类Plugin就可以了。

插件类的方法如下表所示:

getDefault()

取得插件类的实例的方法。插件类是单例的,所以这个方法作为一个静态方法提供。

start()

插件开始时的处理。

stop()

插件停止时的处理。

getLog()

log输出时取得ILog用的方法。

getImageRegistry()

取得管理插件内图像的ImageRegistry类。

getPerferenceStore()

取得保存插件设定的IPerferenceStore类。

getDialogSettings()

取得保存对话框设定的IDialogSettings类。

getWorkbench()

取得IWorkbench的实例。

以上就是根据[Hello World]模板生成的插件的代码讲解,在PDE中为我们准备了很多的模板,大家可以都试试看。

插件的测试与调试

  • 使用JUnit对插件进行测试

Eclipse中已经嵌入了JUnit,我们可以使用JUnit为插件进行单体测试。一般的JUnit是不可以对插件部分(对Eclipse的API依赖的部分)进行测试的,但是在PDE环境中使利用JUnit对插件进行单元测试成为可能。 要想进行测试首先要添加插件的依赖关系,在插件设定页面的[依赖关系(Dependencies)]页面点击[增加(Add)]按钮,添加[org.junit(3.8.2)]作为必须插件(图11)。

图11 增加org.junit插件的依赖关系

接下来,生成测试用例(TestCase)。测试用例和一般的JUnit用例相同,继承junit.framework.TestCase。如下代码中的测试用例说明了,在工作台页面中打开一个视图,并且确认打开的视图处于激活状态。

插件测试用例的示例

public class SampleViewTest extends TestCase {

    public SampleViewTest(String name) throws Exception {
        //取得当前活动的页面
        IWorkbench workbench = PlatformUI.getWorkbench();
        IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
        IWorkbenchPage page = window.getActivePage();

        //打开视图
        page.showView("cn.sf.amateras.sample.views.SampleView");

        //确认打开的视图处于激活状态
        IWorkbenchPart activePart = page.getActivePart();
        assertTrue(activePart instanceof IViewPart);
        assertEquals("cn.sf.amateras.sample.views.SampleView",
                activePart.getSite().getId());
    }

}

当前这个测试用例可以通过在测试类上点右键[执行(Run As)]->[JUnit插件测试(JUnit Plug-in Test)]执行。

图12 执行JUnit插件测试

  • 调试和错误处理

调试插件 用调试模式启动运行时工作台后,像一般的java程序一样,在程序中设置断点就可以了。调试模式的启动可以从manifest编辑器的概要页面,点击[调试Eclipse应用(Lunach an Eclipse Application in Debug mode)],或者点击工具栏上的调试按钮。

在错误发生时,需要做以下两件事: 1)通知使用者 2)记录日志

输出日志 向Eclipse下的[.metadata]文件夹的[/.log]文件进行日志输出。输出日志时使用org.eclipse.core.runtime.ILog接口,通过插件类获得ILog接口的实例。如下代码所示

输出日志

ILog log = Activator.getDefault().getLog();

log.log(new Status(IStatus.OK, Activator.PLUGIN_ID,
    0, "正常消息", null));

log.log(new Status(IStatus.OK, Activator.PLUGIN_ID,
    0, "异常消息", new Exception("输出日志的异常")));

Status对象的构造函数的参数如下表所示。

Status的构造参数

参数
说明

int severty

重要度。候选值有IStatus.OK、IStatus.ERROR、IStatus.INFO、IStatus.WARNING、IStatus.CANCEL。

String pluginId

插件的ID

int code

插件固定的消息code,或者是IStatus.OK。

String message

输出日志的消息。

Throwable exception

输出日志的异常。没有时候添null。

错误通知 错误发生后通知使用者的方法有很多,最简单的方法就是使用JFace的org.eclipse.jface.dialogs.ErrorDialog类。

使用ErrorDialog

try{
    //....
}catch(Exception e){
    IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,
            0, e.toString(), e);
    ErrorDialog.openError(window.getShell(), "错误", "插件出错了!", status);
}

运行时工作台启动时的参数 Eclipse是由很多的插件构成的,在其背后运行着非常复杂的处理,所以也需要相应的内存。特别是,很多的插件在加载庞大的类时,就很容易出现VM常驻(permanent)区域的不足的情况。 通常,Eclipse使用的堆(Heap)区和常驻区的大小可以通过Eclipse安装目录下的eclipse.ini文件进行设定。

默认的eclipse.ini文件

-showsplash

org.eclipse.platform

--launcher.XXMaxPermSize

256m

--launcher.defaultAction
openFile

-vmargs

-Dosgi.requiredJavaVersion=1.5

-Xms40m

-Xmx512m

在插件开发过程中如果出现内存空间不足的时候,也可以通过[运行(Run)]->[运行设定(Run Configurations)]窗口的[参数]tab页中的[VM参数]项来指定空间的大小。

图13 VM参数设定

转载请注明出处,http://www.cnblogs.com/liuzhuo.

Last updated

Was this helpful?