Разработка подключаемых модулей для Eclipse

 

Источник: http://www.ibm.com/developerworks/ru/library/os-ecplug/

David Gallardo

Архитектура, основанная на подключаемых модулях

Eclipse Platform - это интегрированная среда разработки, переданная IBM сообществу сторонников открытого исходного кода. Она примечательна не только суммой денег, которую IBM потратила по ее словам на разработку ($40 миллионов), но скорее тем, на что пошли такие затраты: продуманная, хорошо спроектированная и расширяемая архитектура. Что ценного в Eclipse? Она предоставляет платформу с открытым исходным кодом для создания расширяемой интегрированной среды разработки. Эта платформа позволяет любому желающему создавать инструментальные средства, которые легко интегрируются в эту среду и другие инструментальные средства. Ключом такой плавной интеграции инструментальных средств с Eclipse является понятие подключаемого модуля. За исключением маленького ядра времени исполнения, все в Eclipse является подключаемым модулем. Это означает, что разрабатываемый вами подключаемый модуль интегрируется с Eclipse точно так же, как и другие подключаемые модули; в этом отношении все создаваемые функциональные возможности равноправны. Однако некоторые подключаемые модули более равноправны, чем другие. Workbench и Workspace - это два обязательных модуля платформы Eclipse. Они обеспечивают точки расширения, используемые большинством подключаемых модулей (рисунок 1). Подключаемому модулю необходима точка расширения для функционирования.

Рисунок 1. Eclipse Workbench и Workspace - важнейшие компоненты для поддержки подключаемого модуля

Компонент Workbench содержит точки расширения, которые, например, позволяют вашему модулю расширять пользовательский интерфейс новыми меню и кнопками инструментальной панели, запрашивать уведомление о событиях различного рода и создавать новые виды. Компонент Workspace содержит точки расширения, которые позволяют вам взаимодействовать с ресурсами, включая проекты и файлы. Естественно, Workbench и Workspace не являются единственными компонентами Eclipse, которые могут быть расширены другими подключаемыми модулями. Кроме них есть компонент Debug, который позволяет вашему модулю запускать программу, взаимодействовать с выполняющейся программой и обрабатывать ошибки - все необходимое для создания отладчика. Будучи необходимым для приложений определенного типа, компонент Debug не требуется для большинства приложений. Существует также компонент Team, который позволяет ресурсам Eclipse взаимодействовать с системами управления версиями (VCS), но, если вы не создаете клиентское приложение Eclipse для VCS, компонент Team, как и Debug, не расширяет и не улучшает функциональность Eclipse. Наконец, существует компонент Help, позволяющий вам предоставлять интерактивную документацию и контекстно-чувствительную справочную систему для вашего приложения. Не нужно отрицать, что справочная система является существенной частью профессионального приложения, но она не является необходимой для обеспечения функциональности подключаемого модуля. Предоставляемые каждым из описанных выше компонентов точки расширения документируются в Eclipse Platform Help в разделе справочной информации «Руководства разработчика подключаемых модулей платформы Eclipse». Быстрый взгляд, в частности, на раздел Workbench справки по API вначале приводит в уныние. Вместо погружения в подробности множества доступных точек расширения мы просто рассмотрим простой подключаемый модуль и его компоненты.

Легкое введение в подключаемые модули

Простейшим способом создания подключаемого модуля является использование Plug-in Development Environment (PDE). PDE вместе с Java Development Tooling (JDT) IDE поставляется как стандартное расширение Eclipse. PDE предоставляет мастеров для помощи при создании подключаемых модулей, в том числе пример «Hello, world», который мы здесь и рассмотрим. Из меню Eclipse выберите File=>New=>Other (либо нажмите Ctrl-N) и затем выберите мастер Plug-in Development в левой части диалога Select. В правой части диалога Select выберите Plug-in Project. Нажмите Next. На следующем экране введите имя проекта; я использовал com.example.hello. Снова нажмите Next. На следующем экране обратите внимание на то, что ID подключаемого модуля соответствует имени проекта. Использование имени проекта в качестве ID подключаемого модуля минимизирует шанс конфликта данного модуля с именем другого подключаемого модуля. Опять нажмите Next. На следующем экране предоставляется выбор - создание начального кода подключаемого модуля вручную, либо запуск мастера генерирования кода. Оставьте значение по умолчанию, выберите «Hello, World» и нажмите Next.

Следующий экран запрашивает дополнительную информацию. Обратите внимание на информацию на этом экране: она включает имя подключаемого модуля, номер версии, имя провайдера и имя класса. Как мы увидим далее - это важные части информации о нашем модуле. Вы можете принять значения по умолчанию, предоставляемые мастером. Нажмите Next. На следующем экране примите значения по умолчанию для имени пакета, имени класса и текста сообщения. Оставьте флажок с меткой «Add the action set to the resource perspective» отмеченным. Нажмите Finish. Если появится предупреждение о том, что мастеру нужно разрешить некоторые другие подключаемые модули для завершения, нажмите OK. Через некоторое время мастер закончит работу, и в вашей рабочей области появится новый проект с названием com.example.hello.

С левой стороны рабочего места в Package Explorer есть обзор некоторых элементов, созданных мастером. Большинство из элементов не очень интересны: много .jar-файлов, включенных в classpath (сюда входят классы Eclipse, необходимые для подключаемого модуля и для системы времени исполнения Java) проекта, папка icons, содержащая графику для кнопок инструментальной панели и файл build.properties, содержащий переменные, используемые сценарием автоматической компоновки. Наиболее интересными элементами являются папка src, содержащая исходный код для нашего подключаемого модуля, и файл plugin.xml - файл манифеста подключаемого модуля. Сначала мы рассмотрим plugin.xml.

Файл манифеста подключаемого модуля

Файл манифеста подключаемого модуля, plugin.xml, содержит описательную информацию, которая будет использована Eclipse для интеграции подключаемого модуля в среду. По умолчанию plugin.xml открывается в области редактора манифеста при первом создании подключаемого модуля. Закладки внизу экрана позволяют вам выбрать различные наборы информации о подключаемом модуле. Закладка Welcome отображает сообщение «Welcome to Hello Plug-In» и кратко обсуждает использованные шаблоны и советы по использованию Eclipse для реализации подключаемого модуля. Выбор закладки «Source» позволит вам завершить исходный код файла plugin.xml. Давайте взглянем на различные части файла манифеста подключаемого модуля. Во-первых, это общая информация о подключаемом модуле, включая его имя, номер версии, имя файла классов, реализующих его, и имя .jar-файла.

<?xmlversion="1.0" encoding="UTF-8"?>
	<plugin id="com.example.hello"
   name="Hello Plug-in"
   version="1.0.0"
   provider-name="EXAMPLE"
   class="com.example.hello.HelloPlugin">

   <runtime>
      <library name="hello.jar"/>
   </runtime>
Листинг 1. Файл манифеста подключаемого модуля - общая информация

Далее перечислены подключаемые модули, необходимые для нашего подключаемого модуля.

	<requires>  
	<import plugin="org.eclipse.core.resources"/>
	<import plugin="org.eclipse.ui"/>
	</requires>
	
Листинг 2. Файл манифеста подключаемого модуля - необходимые подключаемые модули

Первый перечисленный подключаемый модуль, org.eclipse.core.resources, является подключаемым модулем Workspace, но он, фактически, не нужен для нашего модуля. Второй модуль, org.eclipse.ui, это Workbench. Нам нужен подключаемый модуль Workbench, поскольку мы будем расширять две его точки расширения, как указано тегами расширения, следующими далее. Первый тег расширения имеет атрибут точки org.eclipse.ui.actionSets. Набор действий - это группа вложений (contributions), которую подключаемый модуль добавляет к пользовательскому интерфейсу рабочей среды (workbench) - меню, элементы меню и инструментальные панели. Действие устанавливает эти группы таким образом, чтобы пользователю было легче управлять ими. Например, элементы меню и инструментальной панели нашего подключаемого модуля Hello будут появляться в перспективе Resource в следствие выбора, который мы сделали во время работы мастера генерирования кода. Пользователь может изменить это, используя пункт меню Window=>Customize Perspective для удаления "Sample Action Set" из элементов, отображаемых в перспективе Resource.

Набор действий содержит два тега: тег menu, описывающий, где и как наш элемент должен появляться в меню рабочей среды, и тег action, описывающий, что он должен делать; в частности, тег action указывает класс, выполняющий действие. Обратите внимание на то, что этот класс отличен от перечисленного выше класса подключаемого модуля.

<extension
         point="org.eclipse.ui.actionSets">
      <actionSet
            label="Sample Action Set"
            visible="true"
            id="com.example.hello.actionSet">
         <menu
               label="Sample &Menu"
               id="sampleMenu">
            <separator
                  name="sampleGroup">
            </separator>
         </menu>
         <action 
               label="&Sample Action"
               icon="icons/sample.gif"
               class="com.example.hello.actions.SampleAction"
               tooltip="Hello, Eclipse world"
               menubarPath="sampleMenu/sampleGroup"
               toolbarPath="sampleGroup"
               id="com.example.hello.actions.SampleAction">
         </action>
      </actionSet>
   </extension>
Листинг 3. Набор действий

Цели многих из атрибутов меню и действий довольно очевидны - например, предоставление текста всплывающей подсказки (tooltip) и указание графического изображения для элемента инструментальной панели. Также обратите внимание на menubarPath в теге action: этот атрибут указывает, какой элемент меню, определенный в теге menu, инициирует действие, определенное в теге action. Более подробная информация об этой и других точках расширения рабочей среды приводится в «Руководстве разработчика подключаемых модулей платформы», в частности в разделе «Подключение к рабочей среде» (руководство доступно из меню help в Eclipse). Второй тег extension был сгенерирован в результате того, что мы выбрали добавление этого подключаемого модуля к перспективе Resource. Этот тег вызывает добавление нашего подключаемого модуля к перспективе Resource во время первого запуска Eclipse и загрузки этого подключаемого модуля.

<extension  
         point="org.eclipse.ui.perspectiveExtensions">
      <perspectiveExtension
            targetID="org.eclipse.ui.resourcePerspective">
         <actionSet
               id="com.example.hello.actionSet">
         </actionSet>
      </perspectiveExtension>
   </extension>
</plugin>
Листинг 4. Тег extension

Если бы этот последний тег extension был пропущен, пользователь должен был бы добавить подключаемый модуль в перспективу Resource (или другую) при помощи Window=>Customize Perspective.

Исходный код подключаемого модуля

Мастер генерирования кода генерирует два Java-файла с исходным кодом, которые вы можете увидеть, открыв папку src в PDE package explorer. Первый файл, HelloPlugin.java, является классом подключаемого модуля и расширяет абстрактный класс AbstractUIPlugin. HelloPlugin отвечает за управление жизненным циклом подключаемого модуля и в более сложных приложениях мог бы отвечать за управление такими элементами, как настройки диалоговых окон и пользовательские предпочтения. HelloPlugin делает не много:

packagecom.example.hello.actions;

import org.eclipse.ui.plugin.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.resources.*;
import java.util.*;

/**
 * Главный класс подключаемого модуля, используемый на рабочем столе.
 */
public class HelloPlugin extends AbstractUIPlugin {
      //Общий экземпляр.
      private static HelloPlugin plugin;
      //Пакет ресурсов.
      private ResourceBundle resourceBundle;
      
      /**
       * Конструктор.
       */
      public HelloPlugin(IPluginDescriptor descriptor) {
            super(descriptor);
            plugin = this;
            try {
                  resourceBundle= ResourceBundle.getBundle(
                       "com.example.hello.HelloPluginResources");
            } catch (MissingResourceException x) {
                  resourceBundle = null;
            }
      }

      /**
       * Возвращает общий экземпляр.
       */
      public static HelloPlugin getDefault() {
            return plugin;
      }

      /**
       * Возвращает экземпляр рабочей области.
       */
      public static IWorkspace getWorkspace() {
            return ResourcesPlugin.getWorkspace();
      }

      /**
       * Возвращает строку из пакета ресурсов подключаемого модуля,
       * либо key, если он не найден.
       */
      public static String getResourceString(String key) {
            ResourceBundle bundle= HelloPlugin.getDefault().getResourceBundle();
            try {
                  return bundle.getString(key);
            } catch (MissingResourceException e) {
                  return key;
            }
      }

      /**
      * Возвращает пакет ресурсов подключаемого модуля,
      */
      public ResourceBundle getResourceBundle() {
          return resourceBundle;
      }
}
Листинг 5. HelloPlugin

Второй исходный файл, SampleAction.java, содержит класс, выполняющий действие, указанное в наборе действий в файле манифеста. SampleAction реализует интерфейс IWorkbenchWindowActionDelegate, который позволяет Eclipse использовать прокси для нашего подключаемого модуля, для того чтобы Eclipse не загружал подключаемый модуль без абсолютной необходимости (такая оптимизация нужна для минимизации используемой памяти и проблем производительности, возникающих при загрузке подключаемого модуля). Методы интерфейса IWorkbenchWindowActionDelegate позволяют нашему модулю взаимодействовать с прокси.

package com.example.hello.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;

/**
 * Наш пример действия реализует действие рабочей среды delegate.
 * Рабочей средой будет создан прокси для действия и 
 * показан в UI. Когда пользователь попытается выполнить действие,
 * будет создано это действие delegate и выполнение будет 
 * делегировано ему.
 * @see IWorkbenchWindowActionDelegate
 */
public class SampleAction implements IWorkbenchWindowActionDelegate {
      private IWorkbenchWindow window;
      /**
       * Конструктор.
       */
      public SampleAction() {
      }

      /**
       * Действие было активизировано. Аргумент 
       * метода представляет "реальное" действие, находящееся  
       * в UI рабочей среды.
       * @see IWorkbenchWindowActionDelegate#run
       */
      public void run(IAction action) {
            MessageDialog.openInformation(
                  window.getShell(),
                  "Hello Plug-in",
                  "Hello, Eclipse world");
      }

      /**
       * Выбор в рабочей среде изменился. Мы здесь
       * можем изменить состояние "реального" действия, 
       * если пожелаем, но это может произойти только после 
       * создания delegate.
       * @see IWorkbenchWindowActionDelegate#selectionChanged
       */
      public void selectionChanged(IAction action, ISelection selection) {
      }

      /**
       * Мы можем использовать этот метод для освобождения любых системных 
       * ресурсов, которые прежде распределили.
       * @see IWorkbenchWindowActionDelegate#dispose
       */
      public void dispose() {
      }

      /**
       * Мы будем кешировать объект window, для того чтобы
       * обеспечить оболочку для диалогового окна сообщения.
       * @see IWorkbenchWindowActionDelegate#init
       */
      public void init(IWorkbenchWindow window) {
            this.window = window;
      }
}
Листинг 6. Методы интерфейса IWorkbenchWindowActionDelegate

Выполнение и отладка подключаемого модуля

При разработке подключаемого модуля в Eclipse было бы неудобно останавливать Eclipse и запускать его повторно с новым подключаемым модулем для его тестирования и отладки. К счастью, Eclipse PDE предоставляет собственную среду разработки, позволяющую вам выполнять подключаемый модуль без его установки в отдельном экземпляре рабочей среды. Для выполнения подключаемого модуля Hello выберите Run=>Run As=>Run-time Workbench для запуска другого экземпляра Workbench с добавленными элементами меню и инструментальной панели нашего модуля (рисунок 5).

Рисунок 5. Подключаемый модуль Hello, работающий в рабочей среде времени исполнения

Мы можем активировать подключаемый модуль, нажав на кнопку инструментальной панели или из меню "Sample Menu". Любой метод вызовет появление окна с заголовком "Hello Plug-in", содержимым "Hello, Eclipse world" и кнопкой OK для его закрытия. Аналогично, мы можем отлаживать подключаемый модуль, выбирая Run=>Debug As=>Run-time Workbench. При этом мы можем в пошаговом режиме проходить по исходному коду, контролировать переменные и т.д. в оригинальной рабочей среде, в то время как подключаемый модуль работает во втором экземпляре рабочей среды. Когда подключаемый модуль протестирован и готов для выпуска, мы должны спакетировать его соответствующим образом для установки в Eclipse.

Пакетирование подключаемого модуля

Eclipse определяет подключаемые модули для загрузки, просматривая свой каталог plugins при запуске. Для установки подключаемого модуля мы должны создать подкаталог в каталоге plugins и скопировать туда наши программные файлы и файл манифеста. Не обязательно, но рекомендуется, чтобы название подкаталога отражало ID подключаемого модуля, за которым следует символ подчеркивания и номер версии. Предположив, что Eclipse установлен в C:\eclipse, мы можем создать каталог:

C:\eclipse\plugins\com.example.hello_1.0.0.

Как и для любого Java-приложения, файлы нашей программы должны быть архивированы в .jar-файл. Файл манифеста нашего модуля, как вы помните, содержит следующую запись:

<runtime> 
      <library name="hello.jar"/>
   </runtime>

Для создания файла hello.jar мы можем экспортировать файлы нашего подключаемого модуля, выделив имя проекта и выбрав File=>Export из меню Eclipse. Выберите JAR file в качестве назначения, нажмите Next и выберите каталог, который мы создали для этого. Затем мы должны также скопировать файл plugin.xml в этот каталог. Вы можете также использовать меню File=>Export (но помните, что надо выбрать File System в качестве назначения). Это все, что требуется для установки подключаемого модуля, но вы должны остановить и повторно запустить Eclipse для его распознавания. Информацию об установленных подключаемых модулях, в том числе номера их версий, можно найти, выбрав "About Eclipse Platform" из меню help. Одной из появившихся на экране кнопок будет кнопка "Plug-in Details"; прокрутите список до конца и найдите подключаемый модуль Hello и номер его версии.

Обновление версии подключаемого модуля

Целью включения номера версии в название каталога является предоставление возможности существования нескольких версий подключаемого модуля на одной и той же системе (загружается только одна версия). Мы можем увидеть, как все это работает, создав обновленную версию подключаемого модуля Hello: например, измените номер версии в файле plugin.xml на «1.0.1» и текст в SampleAction.java на «New and improved Hello, Eclipse world». Выберите Project => Rebuild All из меню Eclipse. Затем экспортируйте файлы проекта в виде JAR в новый каталог подключаемого модуля, например, com.example.hello_1.0.1. Скопируйте новый файл plugin.xml в этот же каталог. После останова и повторного запуска Eclipse будет загружена только новая версия подключаемого модуля.

Фрагменты и функциональности подключаемого модуля

Eclipse состоит из подключаемых модулей, но существуют два других уровня компонентов, которые важно учитывать при разработке подключаемых модулей для Eclipse - фрагменты и функциональности подключаемого модуля. Фрагмент подключаемого модуля, исходя из названия, формирует часть полноценного модуля - целевого подключаемого модуля. Функциональность фрагмента объединяется с функциональностью целевого подключаемого модуля. Фрагмент может быть использован для локализации модуля для других языков или для последовательного добавления функциональных возможностей к существующему подключаемому модулю, когда нет необходимости в полной версии, либо для предоставления зависящей от платформы функциональности. Во многих отношениях фрагмент идентичен подключаемому модулю. Основным отличием является то, что фрагмент не имеет класса подключаемого модуля - жизненный цикл фрагмента управляется его целевым подключаемым модулем. Кроме того, файл манифеста фрагмента, называемый fragment.xml, содержит ID и номер версии целевого подключаемого модуля, а также ID и номер версии фрагмента. Функциональность подключаемого модуля, с другой стороны, вообще не включает в себя кодирование. В соответствии с терминологией архитектуры Eclipse функциональность - это пакетирование группы связанных подключаемых модулей в интегрированный продукт. Например, JDT - это функциональность, состоящая из таких подключаемых модулей, как Java-редактор, отладчик и консоль. Файл манифеста feature.xml описывает функциональность архива. Среди прочего файл манифеста содержит ссылки на подключаемые модули и другие ресурсы, содержащиеся в функциональности - информацию об обновлении, авторском праве и лицензии. В Eclipse первичная функциональность устанавливает внешний вид и поведение платформы Eclipse. Первичная функциональность определяет такие вещи как экран заставки и другие характеристики, указывающие на идентичность Eclipse. Eclipse разрешает иметь только одну первичную функциональность. Таким образом (создавая набор подключаемых модулей, пакетируя их в функциональность и делая эту функциональность первичной) можно изменить торговую марку Eclipse и использовать его для создания совершенно нового и особенного продукта. Загруженный с Eclipse.org продукт имеет первичную функциональность eclipse.org.platform.

Дальнейшие действия

Это введение в подключаемые модули, конечно же, охватывает очень немногое из того, что можно делать с ними. Лучшим ресурсом для изучения подключаемых модулей является «Руководство разработчика подключаемых модулей», доступное из меню help Eclipse. Документация содержит руководство по программированию, справочную информацию по Eclipse API и точкам расширения подключаемых модулей, руководство по программированию примеров, доступных на Eclipse.org, и список часто задаваемых вопросов. Другим отличным ресурсом является сам исходный код Eclipse. В зависимости от ваших интересов вы, возможно, захотите найти примеры расширения других функциональных возможностей рабочей среды, например, редакторов и видов, либо примеры использования SWT (графический API Eclipse). В разделе «Ресурсы» приведены ссылки на ресурсы для дополнительного изучения.

Ресурсы

  1. Оригинал статьи "Developing Eclipse plug-ins. How to create, debug, and install your plug-in".
  2. Документация, статьи и загружаемые файлы Eclipse доступны на Web-сайте Eclipse Project.
  3. Просмотрите полный список подключаемых модулей для Eclipse.
  4. Дополнительная информация о подключаемых модулях на французском языке.
  5. Дополнительная информация по Eclipse приводится в следующих статьях developerWorks:

  6. Подробнее о разработке подключаемых модулей рассказывается в статьях на сайте Eclipse.org.
  7. Ищите необходимые ресурсы в зоне проектов с открытым исходным кодом и в зоне Java-технологии на developerWorks.