Der frühe Vogel fängt den Wurm

Migration auf Eclipse 4: einmal angefangen, gibt es kein Zurück…

Philip Wenig
©shutterstock.com/Gallinago_media

Mit der neuen Eclipse 4 Version .3 „Kepler“ wurde die aktive Weiterentwicklung der 3er-Linie eingestellt. Höchste Zeit also, sich die neue Eclipse 4 Applikationsplattform anzuschauen und eventuell die eigene Anwendung auf die neue Basis zu migrieren. Die neue Plattform hat viele interessante Neuerungen und Verbesserungen mit an Bord. Theoretisch dürfte die Migration einer 3.x-Anwendung also durchaus machbar sein. Was dabei alles schief gehen kann, möchte ich in diesem Artikel am Beispiel von OpenChrom zeigen.

Die Bekanntgabe, dass mit dem 3er-Release der neuen Eclipse 4 Version die 3.x-Linie nicht mehr fortgeführt wird, hat den Ausschlag gegeben. Es ist an der Zeit, sich mit der neuen Applikationsplattform (Eclipse 4 Application Platform) zu beschäftigen. Und genau das hat der frühe Vogel dann auch getan. Daher habe ich mich im Vorfeld mit den neuen Technologien der Plattform eingehend beschäftigt, unter anderem mit dem Buch „Eclipse 4“ [1] und etlichen Tutorials von Lars Vogel [2]. Dabei bin ich zu der Einschätzung gekommen, dass eine Migration der 3.x-basierten Anwendung OpenChrom [3] auf die 4er-Linie durchaus machbar ist.

Eclipse 4: die Probleme offenbaren sich erst in der Praxis

Leider offenbaren sich die Probleme meistens nicht in der Theorie, sondern erst dann, wenn es um die praktische Umsetzung geht. Seit der 4er-Linie von Eclipse stehen grundsätzlich vier Möglichkeiten zur Verfügung, um auf Basis von Eclipse eigene Anwendungen zu entwickeln (Abb. 1). Die Möglichkeit einer 3.x-Anwendung soll hier nicht weiter betrachtet werden. Gerne hätte ich OpenChrom als native 4.x-Anwendung umgesetzt. Dort werden die Anwendung und das GUI über die Datei Application.e4xmi und die Fragmente fragment.e4xmi gesteuert. Die aus 3.x bekannten Advisors (ApplicationActionBarAdvisor, ApplicationWorkbenchAdvisor, ApplicationWorkbenchWindowAdvisor) werden dabei nicht mehr benötigt.

Aus den nachfolgend genannten Gründen musste ich mich jedoch für den Modus einer 4.x-Anwendung mit zusätzlichem Kompatibilitätsmodus entscheiden. Dabei wird die grafische Oberfläche über die *.e4xmi-Dateien gesteuert. Anders als bei einer 3.x-Anwendung mit zusätzlicher 4.x-Funktionalität (Dependency Injection) [4] basiert die gesamte Anwendung bei der 4.x-Variante und zusätzlichem Kompatibilitätsmodus prinzipiell auf der neuen Plattform 4.3 „Kepler“. Der Kompatibilitätsmodus sorgt dafür, dass auch 3.x-Komponenten über das neue Modell platziert und angezeigt werden können.

Abb. 1: Seit der Veröffentlichung der 4er-Linie von Eclipse stehen einem grundsätzlich vier Möglichkeiten zur Verfügung, um eigene Anwendungen auf der Basis von Eclipse zu entwickeln

Im Folgenden möchte ich einige ausgewählte Punkte und entsprechende Lösungsansätze aufzeigen, mit denen ich mich bei der Migration beschäftigen musste.

Views: Project Explorer, Console, Progress und Properties View, Welcome Page

Hier gehen die Probleme schon los. Gerne hätte ich OpenChrom komplett auf die 4er-Plattform umgestellt. Nach einigen Recherchen hat sich aber herausgestellt, dass einige Views einfach noch nicht nativ unter Eclipse 4 verfügbar sind. Insbesondere der „Project Explorer“ und die „Properties View“ sind von zentraler Bedeutung. Ohne den „Project Explorer“ wäre die Funktionalität vieler zusätzlicher Plug-ins (z. B. EGit) nicht vernünftig nutzbar. Nun haben sich die Entwickler glücklicherweise um diese Punkte gekümmert, indem sie einen Kompatibilitätsmodus zur Verfügung stellen. Dieser ermöglicht, dass Views, die unter Eclipse 3.x entwickelt wurden (also von ViewPart abgeleitet werden), auch unter Eclipse 4 genutzt werden können.

Eigentlich wollte ich darauf verzichten, mit dem Kompatibilitätsmodus mehr Komplexität in die Anwendung zu bringen als ohnehin schon vorhanden ist. Aber daran führt kein Weg vorbei. Es ist daher sehr zu begrüßen, dass über diesen Weg die gewünschten Views weiterhin benutzt werden können. Als Class URI wird in der Application.e4xmi dann nicht die Klasse der gewünschten View, sondern die Ressource der Kompatibilitäts-View org.eclipse.ui.internal.e4.compatibility.CompatibilityView angegeben (Abb. 2). Die ID bestimmt die gewünschte 3.x-View. Eine Auflistung gängiger 3.x-Views ist in Tabelle 1 zu finden.

Abb. 2: Einbindung von 3.x-Views im Eclipse-4-Modell über den Kompatibilitätsmodus

Tabelle 1: Auflistung einiger 3.x-Views, die über den e4-Kompatibilitätmodus eingebunden werden können

Aufmacherbild: Western Jackdaw in flight. von Shutterstock / Urheberrecht: Gallinago_media

[ header = Seite 2: Dialoge: Preferences, Marketplace-Dialog, Updates, Import-/Export-Wizards  ]

Dialoge: Preferences, Marketplace-Dialog, Updates, Import-/Export-Wizards

Auch der Einstellungsdialog, die Import-/Export-Wizards und der Marketplace-Dialog sind noch nicht nativ unter Eclipse 4 verfügbar. Hier könnte man sich natürlich auch hinsetzen und eine entsprechende Alternative für die eigene Eclipse-4-Plattform programmieren. Aber ehrlich gesagt finde ich den 3.x-Einstellungsdialog ziemlich gut. Also warum sollte man hier das Rad noch einmal neu erfinden? Durch den Kompatibilitätsmodus kann auch der wohl bekannte 3.x-Einstellungsdialog eingebunden werden. Dazu wird das Kommando zum Öffnen über den ECommandService und einen ParameterizedCommand abgesetzt (Listing 1). Über diesen Weg können übrigens auch andere 3.x-Kommandos aufgerufen werden.

@Execute
void execute(ECommandService commandService, EHandlerService handlerService, Logger logger) {
  
..ParameterizedCommand command = commandService.createCommand("org.eclipse.ui.window.preferences", null);
..if(handlerService.canExecute(command)) {
....handlerService.executeHandler(command);
..} else {
....logger.warn("Der Dialog konnte nicht geöffnet werden.");
..}
}

Auf gleiche Weise wie in Listing 1 dargestellt können auch der Marketplace- und der Updatedialog sowie die Import-/Export-Wizards aufgerufen werden. Eine Auflistung der Kommandos ist in Tabelle 2 zu finden.

Tabelle 2: Auflistung einiger 3.x-Kommandos, die über den Eclipse 4 ECommandService aufgerufen werden können

Perspektiven- und View Switcher

Kommen wir zum dritten großen Showstopper einer reinen Eclipse-4-Anwendung: Es gibt dort noch keinen Perspektiven- und View Switcher. Die gute Nachricht ist: Die beiden kann man relativ einfach erstellen. In Listing 2 sind die prinzipiellen Methodenaufrufe dargestellt, die man zum Wechseln einer Perspektive oder zum Fokussieren einer View benötigt.

@Inject
private MApplication application;
@Inject
private EModelService modelService;
@Inject
private EPartService partService;

public void changePerspective(String perspectiveId) {
  
  MUIElement element = modelService.find(perspectiveId, application);
  if(element instanceof MPerspective) {
    MPerspective perspective = (MPerspective)element;
    partService.switchPerspective(perspective);
  }
}

public void focusView(String viewId) {

  MUIElement element = modelService.find(viewId, application);
  if(element instanceof MPart) {
    MPart part = (MPart)element;
    if(!partService.getParts().contains(part)) {
      partService.createPart(part.getElementId());
    }
    partService.showPart(part, PartState.ACTIVATE);
  }
}

Property Sheet

Wenn man die neuen Dependency-Injection-(DI-)Features und das Definieren von Parts über den Eclipse-4-Mechanismus nutzt, steht einem der gewohnte Aufruf von getSite().setSelction(viewer) nicht mehr zur Verfügung, da die View nicht mehr von ViewPart abgeleitet wird. Nun ja, laut der Anleitung kann man sich zum Bekanntmachen einer Selektion den ESelectionService injizieren lassen. Das Injizieren klappt auch ganz gut (Listing 3). Die Selektion kann dann auch wieder abgefragt werden. So weit, so gut. Nur: Die Eigenschafts-View bekommt davon gar nichts mit. Mittels Kompatibilitätsmodus kann man eine von ViewPart abgeleitete View einbinden. Dabei wird die View klassisch in der Datei plugin.xml definiert. Die ID der View wird dann, wie unter Abbildung 2 gezeigt, über die Kompatibilitätsschicht eingebunden. Es ist jedoch darauf zu achten, dass die IDs genau übereinstimmen.

@Inject
private ESelectionService selectionService;

@PostConstruct
public void createControl() {
 ..
  tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
    
    @Override
    public void selectionChanged(SelectionChangedEvent event) {

      IStructuredSelection selection = (IStructuredSelection)event.getSelection();
      MyObject myInstance = (MyObject)selection.getFirstElement();
      selectionService.setSelection(myInstance);
    }
  });
}

Annotierte Funktionen werden nicht aufgerufen

Eclipse 4 macht reichlich Gebrauch von der neu in die Plattform eingeführten Dependency Injection. So ist es mit @Inject sehr schön möglich, sich Instanzen eines gewünschten Objekts injizieren zu lassen oder mit @PostConstruct den Aufruf einer bestimmten Methode festzulegen:

@Inject
•@PostConstruct
•@PreDestroy
•@Focus
•…

Nur habe ich festgestellt, dass die Methoden einfach nicht aufgerufen wurden bzw. die zu injizierenden Instanzen Null waren. Wenn das passiert, sollte man prüfen, ob in der MANIFEST.MF-Datei im Reiter IMPORTED PACKAGES das Paket javax.annotation referenziert wird (Abb. 3).

Abb. 3: Ohne das Einbinden des Pakets „javax.annotation“ über den Reiter IMPORTED PACKAGES funktioniert bei den Annotationen gar nichts

[ header = Seite 3: Status-Line ]

Status-Line

Wie man der Eclipse-4-Beschreibung [5] entnehmen kann, braucht man zum Setzen einer Statusnachricht nur eine Instanz von IStatusLine. Diese wird mittels @Inject zur Verfügung gestellt. Mit setMessage(text) wird der entsprechende Text dann in der Statuszeile dargestellt. Unter 3.x musste man sich eine Instanz vom IStatusLineManager mittels actionBars.getStatusLineManager() holen. An sich klingt das mit dem Injizieren sehr vernünftig. Nur gibt es dabei einen Haken: Es funktioniert einfach nicht.

Eclipse-3.x-/4.x-Editoren

Unter Eclipse 4 kann jeder Part ein Editor sein. Es ist nicht mehr nötig, von EditorPart oder MultiPageEditorPart abzuleiten. Das ist großartig. Außerdem ist es möglich, Editoren an jeder beliebigen Stelle in der grafischen Oberfläche zu platzieren. Ein 4.x-Editor kann über den Aufruf MBasicFactory.INSTANCE.createInputPart() erzeugt werden. Lars Vogel hat hierzu eine ausführliche Anleitung geschrieben [6]. Dabei ist es wichtig zu erwähnen, dass man beim Schließen des Editors dafür sorgt, dass der Editor wieder vom MPartStack entfernt wird (Listing 4).

@Inject
private EModelService modelService;
@Inject
private MInputPart inputPart;

@PreDestroy
private void preDestroy() {

  if(modelService != null) {
    MPartStack partStack = (MPartStack)modelService.find("MyEditorID", application);
    partStack.getChildren().remove(inputPart);
  }
  ...
}

Das mit den 4.x-Editoren funktioniert also. Da der Projektexplorer aber weiterhin Verwendung finden soll, ist es überaus wichtig, dass sich auch alte 3.x-Editoren nahtlos öffnen lassen. Dirk Fahland hat zum Einbinden von 3.x-Editoren unter Eclipse 4 eine sehr lesenswerte Anleitung geschrieben [7]. Das funktioniert soweit auch sehr gut. Hier sollte man jedoch beachten, dass das Element, das die ID org.eclipse.ui.editorss des 3.x-Editors erhält, ein Element vom Typ MPlaceholder sein muss (Abb. 4). Ansonsten erhält man folgende unschöne Fehlermeldung (Listing 5).

Abb. 4: Die 3.x-Editor-ID muss über einen „Placeholder“ eingebunden werden

!MESSAGE Exception while dispatching event org.osgi.service.event.Event [topic=org/eclipse/e4/ui/model/ui/ElementContainer/selectedElement/SET] to handler org.eclipse.e4.ui.services.internal.events.UIEventHandler@581bb02e
!STACK 0
java.lang.ClassCastException: org.eclipse.e4.ui.model.application.ui.advanced.impl.AreaImpl cannot be cast to org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder
...

Allerdings ließen sich bei mir die Editoren nicht öffnen. Anstelle des gewünschten Editors habe ich eine Fehlermeldung erhalten, dass das Element IDfind.ext nicht gefunden werden konnte (Abb. 5). Dabei wurde eine Fehlermeldung geworfen, die aus dem Kompatibilitätsmodus stammt (Listing 6). Abhilfe kann hier geschaffen werden, indem im ApplicationActionBarAdvisor, der ja im 4.x-Modus mit dem Kompatibilitätsmodus weiterhin benutzt wird, beim Edit-Menü die Konstante IWorkbenchActionConstants.FIND_EXT hinzugefügt wird (Listing 7).

Abb. 5: Beim Öffnen von 3.x-Editoren kam es unter 4.x zu diesem Fehler

!ENTRY org.eclipse.e4.ui.workbench 4 0 2013-04-26 08:23:27.901
!MESSAGE Unable to create class 'org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor' from bundle '364'
!STACK 0
org.eclipse.e4.core.di.InjectionException: java.lang.IllegalArgumentException: can't find Idfind.ext
...
protected void fillMenuBar(IMenuManager menuBar) {
  MenuManager editMenu = new MenuManager("&Edit", IWorkbenchActionConstants.M_EDIT);
  menuBar.add(editMenu);
  editMenu.add(new GroupMarker(IWorkbenchActionConstants.FIND_EXT));
  ...

Standardperspektive

Das Setzen der Standardperspektive konnte man unter 3.x durch einen Eintrag in die Datei plugin_customization.ini über defaultPerspectiveId = … erreichen. Das funktioniert unter der neuen Plattform nicht mehr. Man kann sich mittels eines Add-ons unter Eclipse 4, durch Aufruf der PostConstruct-Methode, den MPerspectiveStack holen und die gewünschte MPerspective über setSelectedElement(…) setzen. Das geht allerdings noch nicht, siehe Bug #377981 [8].

[ header = Seite 4: Min-/Max-Buttons funktionieren nicht ]

Min-/Max-Buttons funktionieren nicht

Da ich bei der Migration mit den ersten Meilensteinen der 4.3-Entwicklung angefangen habe, trat das Problem auf, dass die Min-/Max-Buttons nicht richtig funktionierten. Die Min-/Max-Funktionalität kann über ein Add-on dem Application.e4xmi-Modell hinzugefügt werden. Dabei wird in der e4xmi-Datei im Bereich ADDONS die ID org.eclipse.e4.ui.workbench.addons.minmax mit folgendem Class-URI hinzugefügt (Abb. 6): bundleclass://org.eclipse.e4.ui.workbench.addons.swt/org.eclipse.e4.ui.workbench.addons.minmax.MinMaxAddon

Bei den ersten Meilensteinen der 4.3er-Reihe wurden leider keine eindeutigen IDs beim Anlegen neuer Elemente wie PartSashContainer, PartStacks, Parts und weiteren vergeben. Und das mag die Min-/Max-Funktionalität nun mal gar nicht. Der Fehler ist mittlerweile behoben. Allerdings sollte man tunlichst darauf achten, dass die IDs der angelegten Elemente eindeutig sind. Wenn das der Fall ist, funktionieren auch die Min-/Max-Buttons wieder wie gewohnt.

Abb. 6: Die Min-/Max-Funktionalität wird über ein Add-on eingebunden

Erweiterungen: Menü- und Toolbareinträge werden nicht angezeigt

Ähnlich wie beim alten 3.x-Mechanismus mit der Datei plugin.xml können unter Eclipse 4 Erweiterungen zum Modell Application.e4xmi über die Datei fragment.e4xmi beigetragen werden. Das Fragment wird über die plugin.xml-Konfiguration referenziert (Listing 6). Obwohl das Fragment korrekt eingebunden wurde und dieses auch korrekt in den build.properties des Plug-ins dem Build hinzugefügt wurde, war von den Menüerweiterungen in der Applikation weit und breit nichts zu sehen. Wenn das passiert, kann es sein, dass das Plug-in zu früh geladen wurde. Zu früh bedeutet, dass es vor dem Plug-in geladen wurde, das die Menüs und Toolbars definiert, zu dem es Erweiterungen liefern soll. Das Problem kann behoben werden, indem man eine Abhängigkeit zum Basis-Plug-in setzt, das die Erweiterungen aufnehmen soll. Dann klappt es auch mit den Menü- und Toolbarerweiterungen.

<plugin>
  <extension
    id="net.openchrom.ui.modelContribution"
    point="org.eclipse.e4.workbench.model">
    <fragment
      uri="fragment.e4xmi">
    </fragment>
  </extension>
...

[ header = Seite 5: Fazit ]

Fazit

Grundsätzlich eröffnet die neue Eclipse-4-Applikationsplattform aus meiner Sicht viele neue Möglichkeiten und ist für zukünftige Herausforderungen gut gewappnet. Möchte man eine komplett neue Anwendung erstellen, ist die neue Eclipse-4-Plattform sicher eine gute Wahl. Man sollte sich der noch bestehenden Einschränkungen aber bewusst sein. Wer zum Beispiel die Konsole oder den Projektexplorer in seiner eigenen Anwendung wiederverwenden möchte, wird bei einer reinen Eclipse-4-Anwendung nicht fündig werden. Diese Dinge müssen also selbst implementiert werden. Nun gibt es ja auch den 3.x-Kompatibilitätsmodus, über den sich die gewünschten Views einbinden lassen. Die Anwendung wird dadurch allerdings komplexer. Bei der Migration meiner bestehenden Eclipse-3.x-Anwendung OpenChrom auf Eclipse 4 hatte ich das Glück, dass mir Lars Vogel und Markus Alexander Kuppe von vogella [9] geholfen haben. Alleine hätte ich das in dem Umfang sicher nicht bewerkstelligen können. Bei der Migration einer bestehenden 3.x-Anwendung sollte man daher entweder noch ein Release abwarten oder einen entsprechenden Personal- bzw. Zeitpuffer einplanen. Empfehlenswert ist nach wie vor eine eingehende Beschäftigung mit der neuen Plattform. Zu diesem Thema gibt es mittlerweile die eine oder andere Lektüre ([1], [10], „Lesetipp“). Ich hoffe, dass dieser Artikel einen Anreiz gegeben hat, über eine Migration auf die neue Plattform nachzudenken.

Lesetipp
Einen guten Einstieg in die Eclipse-4-Plattform bietet auch das Buch von Marc Teufel und Jonas Helming, erschienen bei entwickler.press.
Geschrieben von
Philip Wenig
Philip Wenig
Dr. Philip Wenig ist Gründer der Open-Source-Software OpenChrom (http://www.openchrom.net) und Geschäftsführer der Lablicate UG (http://lablicate.com). Er beschäftigt sich hauptsächlich mit der Entwicklung von Software für den Bereich der Chromatographie und Massenspektrometrie (GC/MS). Darüber hinaus beteiligt sich seine Firma Lablicate UG aktiv an der Science Working Group (WG) der Eclipse Foundation (http://science.eclipse.org).
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.