T.M. SoftStudio

feci quod potui, faciant meliora potentes

Купить полную версию книги "Среда разработки Eclipse 4: Руководство разработчика"



Создание RCP-приложений

Создание Eclipse 4 RCP-приложения

Dependency Injection (DI) и Eclipse-контекст

Dependency Injection (DI) – технология, позволяющая вставлять ссылку на нужный объект в виде поля или свойства класса без участия оператора new, при этом среда выполнения обеспечивает внедрение определенной реализации объекта при создании экземпляра класса.

Для указания среде выполнения о необходимости внедрения объекта используются аннотации.

Спецификация Java Specification Request 330 (JSR-000330) определяет две аннотации пакета javax.inject для DI-внедрения:

  • @Inject – маркирует конструкторы, методы и поля, использующие внедренные объекты в виде параметров. Так как объекты полей и методов внедряются после вызова конструктора, их нельзя использовать в конструкторе.

  • @Named – для аннотации @Inject уточняет определенную реализацию или экземпляр внедряемого объекта.

Для уменьшения использования синглтонов глобального доступа и тесных связей, платформа Eclipse 4 также вводит поддержку DI-внедрения, аналогично фреймворкам Spring или Guice, с помощью плагинов org.eclipse.e4.core.di, org.eclipse.e4.core.di.extensions и org.eclipse.e4.ui.di.

В рамках реализации DI-технологии платформа Eclipse 4, помимо аннотаций @Inject и @Named, обеспечивает поддержку следующих аннотаций:

  • @Singleton (пакет javax.inject) – маркирует класс, экземпляр которого может быть создан только один раз для области внедрения – области приложения.

  • @Optional (пакет org.eclipse.e4.core.di.annotations) – если среда выполнения не может найти внедряемый объект, тогда для параметров внедряется нулевое значение, вызов методов пропускается, значения полей не внедряются.

  • @Active (пакет org.eclipse.e4.core.contexts) – для аннотации @Inject обеспечивает внедрение объекта из активного в данный момент IEclipseContext-контекста.

  • @Preference(nodePath="my.plugin.id", value="key_preference") (пакет org.eclipse.e4.core.di.extensions) – для аннотации @Inject обеспечивает внедрение значения предпочтения из предпочтений IEclipsePreferences.

  • @Creatable (пакет org.eclipse.e4.core.di.annotations) – если внедряемый объект отсутствует в контексте среды выполнения, тогда экземпляр класса, промаркированного данной аннотацией, автоматически создается при внедрении.

  • @AboutToShow, @AboutToHide (пакет org.eclipse.e4.ui.di) – маркируют методы класса, связанного с элементом DynamicMenuContribution и обеспечивающего создание элемента меню программным способом. Аннотация @AboutToShow маркирует метод, вызываемый средой выполнения при открытии контейнера меню для добавления нового элемента в список, а аннотация @AboutToHide маркирует метод, вызываемый средой выполнения при закрытии контейнера меню для освобождения дополнительных ресурсов.

  • @GroupUpdates (org.eclipse.e4.core.di.annotations) – для аннотации @Inject маркирует метод, автоматически вызываемый при вызове метода IEclipseContext.processWaiting() после изменения внедряемых объектов.

  • @EventTopic (пакет org.eclipse.e4.core.di.extensions), @UIEventTopic (пакет org.eclipse.e4.ui.di) – для аннотации @Inject маркируют аргументы метода, который автоматически вызывается при генерации событий.

Аннотации поведения:

  • @PostConstruct, @PreDestroy (пакет javax.annotation) – маркируют методы, вызываемые средой выполнения после внедрения объекта класса и перед его освобождением.

  • @Focus (пакет org.eclipse.e4.ui.di) – маркирует метод Part-класса, для его автоматического вызова при получении фокуса Part-частью. При этом дочерние элементы части должны быть способны получить фокус.

  • @Persist (пакет org.eclipse.e4.ui.di) – маркирует метод, вызываемый средой выполнения при вызове обработчика, используемого для сохранения изменений содержимого части с применением сервиса EPartService.

  • @PersistState (пакет org.eclipse.e4.ui.di) – маркирует метод, вызываемый перед вызовом метода с аннотацией @PreDestroy, для сохранения состояния.

  • @CanExecute, @Execute (пакет org.eclipse.e4.core.di.annotations) – маркируют методы обработчика событий GUI-интерфейса для их автоматического вызова.

Аннотации жизненного цикла, используемые в обработчике, который зарегистрирован в файле plugin.xml:

<property

name="lifeCycleURI"

value="bundleclass://E4RCP/e4rcp.LifeCycleManager">

</property>

  • @PostContextCreate (пакет org.eclipse.e4.ui.workbench.lifecycle) – маркирует метод, вызываемый после создания IEclipseContext-контекста объекта MApplication, для добавления дополнительных объектов в контекст.

  • @ProcessAdditions и @ProcessRemovals (пакет org.eclipse.e4.ui.workbench.lifecycle) – маркируют метод, вызываемый перед визуализацией модели приложения, для добавления или удаления элементов модели.

  • @PreSave (пакет org.eclipse.e4.ui.workbench.lifecycle) – маркирует метод, вызываемый перед сохранением модели приложения, для модификации модели.

Среда выполнения обеспечивает DI-внедрение объектов, которые присутствуют в IEclipseContext-контексте E4-приложения.

Среда выполнения E4-приложения отслеживает внедренные объекты и, если они изменяются, производит их повторное внедрение для полей и методов, промаркированных аннотацией @Inject (исключая конструкторы и методы с аннотацией @PostConstruct).

При запуске E4-приложения среда выполнения создает контекст, представленный объектом, реализующим интерфейс org.eclipse.e4.core.contexts.IEclipseContext.

IEclipseContext-контекст содержит объекты, которые поддерживаются DI-внедрением.

Платформа Eclipse 4 поддерживает IEclipseContext-контекст приложения, чтобы сделать независимым выполнение приложения от специфической реализации платформы.

IEclipseContext-контекст представляет собой хэш-таблицу, содержащую пары ключ-значение, где ключ – это строка, как правило, имя класса, а значение – объект. При этом значение ключа вычисляется IEclipseContext-контекстом динамически.

IEclipseContext-контекст может образовывать иерархическую структуру, в которой дочерние контексты наследуют или переопределяют значения родительских контекстов.

Иерархическая структура IEclipseContext-контекста Е4-приложения следует структуре модели приложения, так как такие объекты модели как MApplication, MInputPart, MPart, MPerspective, MPopupMenu, MTrimmedWindow, MWindow реализуют интерфейс org.eclipse.e4.ui.model.application.ui.MContext, обеспечивающий создание локального контекста. Корневой узел иерархии представляет контекст объекта MApplication, над которым существует только OSGi-реестр.

При выполнении DI-внедрения среда выполнения начинает поиск объекта по его ключу с локального контекста, связанного с объектом модели приложения, и если не находит нужный объект поиск осуществляется вверх по иерархии контекстов вплоть до OSGi-реестра.

По умолчанию среда выполнения включает в IEclipseContext-контекст:

  • Объекты модели приложения, реализующие интерфейс MContext.

  • Eclipse-сервисы и объекты: ECommandService, EHandlerService, EPartService, EModelService, ESelectionService, EBindingService, EContextService, Adapter, StatusReporter, Logger, IEventBroker, IPresentationEngine, IShellProvider, IServiceConstants, Composite.

Кроме того, IEclipseContext-контекст обеспечивает доступ при DI-внедрении к OSGi-сервисам и Preferences-предпочтениям.

Для доступа к объектам IEclipseContext-контекста используются аннотации DI-внедрения:

@Inject

public ViewPart(Composite parent) {

. . .

@Execute

public void execute(IEclipseContext context) {

. . .

@PostConstruct

public void createControls(Composite parent) {

. . .

При применении таких аннотаций как @PostConstruct, @PreDestroy, @Focus и др. нет необходимости использовать аннотацию @Inject, так как среда выполнения E4-приложения также будет выполнять и DI-внедрение для аргументов промаркированного метода.

Для доступа к локальному контексту объекта модели приложения можно воспользоваться методом getContext() интерфейса MContext, при этом можно внести собственный объект в IEclipseContext-контекст:

@PostConstruct

public void createControls(Composite parent, MApplication application) {

IEclipseContext context = application.getContext();

context.set("key", "value");

context.declareModifiable("key");

. . .

}

Использование @Named и IServiceConstants

Интерфейс org.eclipse.e4.ui.services.IServiceConstants предоставляет набор констант, которые можно использовать совместно с аннотацией @Named.

Поле ACTIVE_SELECTION обеспечивает DI-внедрение установленного с помощью сервиса ESelectionService объекта:

Установка выбранного объекта:

import javax.annotation.PostConstruct;

import javax.inject.Inject;

import org.eclipse.e4.ui.di.Focus;

import org.eclipse.e4.ui.workbench.modeling.ESelectionService;

import org.eclipse.jface.viewers.ISelectionChangedListener;

import org.eclipse.jface.viewers.IStructuredSelection;

import org.eclipse.jface.viewers.SelectionChangedEvent;

import org.eclipse.jface.viewers.TableViewer;

import org.eclipse.swt.SWT;

import org.eclipse.swt.layout.GridData;

import org.eclipse.swt.layout.GridLayout;

import org.eclipse.swt.widgets.Composite;

import org.eclipse.swt.widgets.Label;

public class SamplePart {

private Label label;

private TableViewer tableViewer;

@Inject ESelectionService selectionService;

@PostConstruct

public void createComposite(Composite parent) {

parent.setLayout(new GridLayout());

label = new Label(parent, SWT.NONE);

label.setText("Sample table");

tableViewer = new TableViewer(parent);

tableViewer.add("Sample item 1");

tableViewer.add("Sample item 2");

tableViewer.add("Sample item 3");

tableViewer.add("Sample item 4");

tableViewer.add("Sample item 5");

tableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));

tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {

@Override

public void selectionChanged(SelectionChangedEvent event) {

IStructuredSelection selection = (IStructuredSelection)

tableViewer.getSelection();

selectionService.setSelection(selection.getFirstElement());

}}); }

@Focus

public void setFocus() {

tableViewer.getTable().setFocus();

}}

Внедрение выбранного объекта:

import javax.inject.Named;

import org.eclipse.e4.core.di.annotations.Execute;

import org.eclipse.e4.ui.services.IServiceConstants;

import org.eclipse.swt.SWT;

import org.eclipse.swt.widgets.MessageBox;

import org.eclipse.swt.widgets.Shell;

public class SelectionHandler {

@Execute

public void execute( @Named(IServiceConstants.ACTIVE_SELECTION) String item, @Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {

MessageBox dialog = new MessageBox(shell, SWT.OK| SWT.CANCEL);

dialog.setMessage(item);

dialog.open();

}}

Поле ACTIVE_CONTEXTS обеспечивает DI-внедрение активного в данный момент IEclipseContext-контекста.

Поле ACTIVE_PART обеспечивает DI-внедрение активной в данный момент Part-части:

@Execute

public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, @Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {

MessageBox dialog = new MessageBox(shell, SWT.OK| SWT.CANCEL);

dialog.setMessage(part.getLabel());

dialog.open();

}

Поле ACTIVE_SHELL обеспечивает DI-внедрение активного в данный момент Shell-окна.

Использование аннотаций жизненного цикла

Создадим в проекте E4-приложения класс с аннотациями @PostContextCreate и @ProcessAdditions:

import org.eclipse.e4.ui.model.application.MApplication;

import org.eclipse.e4.ui.model.application.ui.basic.MWindow;

import org.eclipse.e4.ui.workbench.lifecycle.*;

import org.eclipse.e4.ui.workbench.modeling.EModelService;

import org.eclipse.swt.SWT;

import org.eclipse.swt.widgets.MessageBox;

import org.eclipse.swt.widgets.Shell;

public class LifeCycleManager {

@PostContextCreate

void postContextCreate() {

final Shell shell = new Shell(SWT.INHERIT_NONE);

MessageBox dialog = new MessageBox(shell, SWT.OK| SWT.CANCEL);

dialog.setMessage("Do you want open this application?");

dialog.open();

}

@ProcessAdditions

void processAdditions(MApplication application, EModelService modelService) {

MWindow window = (MWindow)modelService.find("e4rcp.trimmedwindow.0", application);

window.setWidth(1000);

}}

В методе с аннотацией @PostContextCreate создается диалоговое окно, которое будет отображаться пользователю при запуске приложения перед отображением главного окна приложения.

В методе с аннотацией @ProcessAdditions перед визуализацией модели приложения изменяются размеры главного окна приложения.

Для регистрации обработчика LifeCycleManager во вкладке Overview редактора Plug-in Manifest Editor нажмем на ссылку Extensions и во вкладке Extensions нажмем правой кнопкой мышки на точке расширения продукта. Выберем команду New | property и в поле name свойства введем lifeCycleURI, а в поле value введем URI-адрес обработчика bundleclass://E4RCP/e4rcp.LifeCycleManager:

<property

name="lifeCycleURI"

value="bundleclass://E4RCP/e4rcp.LifeCycleManager">

</property>

Теперь методы с аннотациями жизненного цикла будут автоматически вызываться средой выполнения.


Создание Eclipse 4 RCP-приложения. Взаимодействие между компонентами Е4-приложения