Eclipse Extension Points und Extensions

Eingetragen bei: Eclipse, RCP | 1

Eclipse beinhaltet ein hoch modulares Konzept um Erweiterungen Plugin-übergreifend realisieren zu können. Das zu erweiternde Plugin bietet einen Extension-Point an, an dem andere Plugins mit ihren Extensions andocken können. Beide Arten an Plugins müssen hierbei zwangsläufig im Manifest als singleton definiert sein.

Um einen Extension-Point zu definieren, wird die plugin.xml Datei des zu erweiternden Bundles geöffnet und zum Reiter Extension Points gewechselt. Sofern keine plugin.xml Datei existiert, kann alternativ im Manifest (MANIFEST.MF) der genannte Reiter aktiviert werden, Eclipse erstellt nun automatisch die plugin.xml Datei. Nun kann ein Extension-Point erzeugt werden, als ID und Namen erhält er im folgenden Beispiel den Wert de.mz.myExtensionPoint und myExtensionPoint.


Nach erfolgreicher Erstellung des Extension-Points wird automatisch das dazugehörige Schema geöffnet. Auch wenn es nicht zwingend notwendig ist, sollten alle Attribute im Schema – Reiter Definition – definiert werden. Nur so können die Felder beim Anlegen einer Erweiterung bequem im Plug-In Manifest Editor über die UI angegeben werden können. Will man später Veränderungen am Schema vornehmen, so ist dieses in der Dateistruktur des Projektes unter schema/myExtensionPoint.exsd zu finden.

Hier wird nun ein neues Element mit dem Namen client erzeugt, dem zwei Attribute zugewiesen werden. Das Erste Attribut hat den Namen class und ist vom Typ Java. Hier hat man nun die Möglichkeit ein Interface zu hinterlegen, welches von der im Attribut class verwiesenen Klasse zu implementieren ist. Im folgenden Beispiel ist das zu implementierende Interface IMyExtension.

Das Interface selber enthält für Beispielzwecke die Methode doSomething:

public interface IMyExtension {
public void doSomething(String text);
}

Das zweite Attribut erhält den Namen text und ist vom Typ String. Hier sind keine weiteren Einstellungen nötig.

Per Context-Menü wird der extension zunächst ein Choice-Element zugewiesen, welches wiederum den Eintrag client erhält. Damit die Extension beliebig viele Client-Einträge erhalten kann, wird die Max Occurrences des Client-Elements auf Unbounded gesetzt. Eine Extension kann also mehrere Erweiterungen enthalten.

Die Plugin.xml hat nun folgenden Eintrag erhalten:

<extension-point id=“de.mz.myExtensionPoint“ name=“myExtensionPoint“ schema=“schema/myExtensionPoint.exsd“/>

Damit andere Bundles nun tatsächlich den Extension-Point erweitern können, müssen sie das Interface IMyExtension implementieren können. Daher muss im Manifest das Package des Interfaces exportiert werden:

Export-Package: de.mz

Damit ist die Definition des Extension-Points abgeschlossen und wir können uns der Erstellung einer Extensions zuwenden. Öffnen wir hierzu die plugin.xml Datei des Bundles, welches den Extension-Point erweitern soll. Auf dem Reiter Extensions kann zwischen den möglichen Erweiterungen gewählt werden, auch der zuvor erstelle Extension-Point de.mz.myExtensionPoint wird hier aufgeführt. Per Context-Menü können hier die Client-Erweiterungen hinzugefügt werden. Für die im Schema deklarierten Attribute stehen im Plug-In Manifest Editor Eingabehilfen zur Verfügung, so kann bequem für das class Attribut eine Implementierung und für das text Attribut ein String angegeben werden.

Diese Einstellung führt zum folgenden Eintrag in der plugin.xml Datei:

<extension point=“de.mz.myExtensionPoint“>
<client
class=“de.mz.MyExtensionImpl“
text=“Hallo Welt“>
</client>
</extension>

Extension-Point und eine dazu passende Extension wurden bereits erstellt, nur Verwendung findet die Erweiterungen bislang noch nicht. Doch hierzu bietet Eclipse die ExtensionRegistry an, auf die man über die Runtime-Platform Zugriff erhält:

IConfigurationElement[] extensions = Platform.getExtensionRegistry().getConfigurationElementsFor(„de.mz.extension.example.myExtensionPoint“);
for (IConfigurationElement extension : extensions) {
try {
String text = extension.getAttribute(„text“);
IMyExtension myExtension = (IMyExtension) extension.createExecutableExtension(„class“);
myExtension.doSomething(text);
// do with myExtension what you have to do
} catch (CoreException e) {
// do some logging
}
}

In obigem Beispiel erhält man alle Erweiterungen die zum Extension-Point de.mz.extension.example.myExtensionPoint gehören. Nun können die Attribute der einzelnen Erweiterungen erfragt werden – hierbei ist es nicht relevant, ob diese im Schema definiert sind – und für das Klassen-Attribut ein entsprechendes Objekt erstellen werden (createExecutableExtension). Bei einem optionalen Klassen-Feld macht es Sinn, sich zunächst zu vergewissern, dass das Attribut einen Wert zugewiesen bekommen hat. Andernfalls wird nämlich eine CoreException geworfen, die über diese Abfrage verhindert werden kann.

Auch wenn das Beispiel auf die Eclipse 3.x Plattform ausgelegt ist, funktioniert der Mechanismus grundsätzlich auch bei Eclipse 4. Hier spart man sich den Umweg über die Runtime-Platform, da sich die ExtensionRegistry bequem per Dependency Injection injizieren lässt.

Will man das Beispiel testen, kann das Laden der Extensions in einem Activator vorgenommen werden, der hierfür lediglich im Manifest eingetragen werden muss:

Bundle-Activator: de.mz.Activator

Nun kann das Extension-Point Bundle als OSGI Framework ausgeführt werden. Treten hierbei Fehler auf, sollten in der Run-Configuration zunächst alle Bundles deselektiert und anschließend nur die Plugins ausgewählt werden, die den Extension-Point und die Extensions beinhalten. Natürlich werden auch Eclipse spezifische Bundles benötigt, die sich über einen Klick auf Add Required Bundles hinzufügen lassen.

Restlet – REST im OSGi Kontext

Eingetragen bei: Eclipse, Java, RCP | 2

Der nachfolgende Artikel beschäftigt sich mit der Erstellung einer Client-Server Architektur, die mittels REST-Schnittstelle kommuniziert und auf dem OSGi-Framework aufbaut. Als REST-Framework wird http://www.restlet.org/ verwendet.

Zur Zeit liegt Restlet in der aktuellen Version 2.0.10 unter http://www.restlet.org/downloads/ zum Download bereit.

Zunächst wird für die Eclipse IDE eine neue Target-Platform erstellt, der als Location die Software Site http://download.eclipse.org/releases/indigo – die Indigo Update Site – hinzugefügt und hier die Equinox Target Components ausgewählt werden. Weiterhin wird als zweite Location auf das lib-Directory des entpackten Restlet-Archives verwiesen.

Kommen wir nun zur eigentlichen Programmierung. Insgesamt werden drei Plug-in Projects benötigt, jeweils ein Client/Server-Projekt und ein Projekt, welches die POJOs beinhaltet, die sowohl auf dem Client, als auch auf dem Server benötigt werden. In Letzteres wird eine User-Klasse erstellt, die zunächst nur aus Vor- und Nachname besteht.

Auf der Server-Seite wird eine eigene Implementierung der Klasse ServerResource benötigt, die eine Methode bereitstellt, um einen beliebigen User zu erhalten:

public class UserResource extends ServerResource {

@Get
public User getUser() {
return new User(„Max“, „Mustermann“);
}
}

Um beim Starten bzw. Stoppen des Server-Bundles den von Restlet bereitgestellten Jetty-Server hoch bzw. herunterzufahren, sind folgende zusätzliche Einträge im Server-Activator nötig:

    private Server server;
private int port = 8182;

public void start(BundleContext bC) throws Exception {
// … do what you have to do, while starting
server = new Server(Protocol.HTTP, port, UserResource.class);
server.start();
}

public void stop(BundleContext bC) throws Exception {
// … do what you have to do, while stopping …
server.stop();
}

Um den Server starten zu können, wird eine OSGI-Framework Run-Configuration benötigt, die zusätzlich zu den Equinox Target Components die Restlet-Bundles beinhaltet. Sollten einige der Restlet-Extensions Probleme bereiten, können diese getrost weg geklickt werden. Nun kann die soeben erstellte Run-Configuration ausgeführt und unter der URL http://localhost:8182/ die UserResource aufgerufen werden.

Natürlich sollte die UserResource nicht nur im Browser abrufbar sein, sondern von einem OSGi-Client konsumiert werden. Daher wird noch ein weiteres Bundle benötigt, wobei die Kommunikation mit dem Server denkbar einfach einfällt:

ClientResource clientResource = new ClientResource(„http://localhost:8182“);
User user = clientResource.get(User.class);

Wie man sieht, verwendet der Client ebenfalls das User-POJO, wobei die Serialisierung bzw. Deseriablisierung des User-Objekts vom Restlet-Framework umgesetzt wird. Dadurch lässt sich schnell und einfach eine REST-Kommunikation im OSGI Kontext realisieren. Zusätzlich zum OSGI Framework (Edition for Java SE) steht das Restlet-Framework noch für die Google AppEngine, GWT und die Android Entwicklung zur Verfügung. Schön das man nicht für jede Plattform ein unterschiedliches REST-Framework verwenden muss.

Eclipse Libra

Eingetragen bei: Eclipse, Java, RCP | 0

Bei Eclipse Libra handelt es sich um ein Unter-Projekt vom Web-Tools-Platform-Projekt (WTP), welches den Funktionsumfang von WTP und dem Plug-in Development Environment (PDE) vereint. So können in einem WTP-Projekt auch die Werkzeuge eines PDE-Projektes genutzt werden.

Für die Installation von Libra unter der aktuellen Eclipse Version Indigo reicht es, auf der Indigo Update-Site die Bundles OSGI Bundle Facet und WAR Products zu installieren.

Erstellt man ein Dynamic Web Project können auf der ersten Seite des Wizards unter Configuration die Project Facets konfiguriert werden. Nach der Installation der oben genannten Pakete ist hier der Menüpunkt OSGI Bundle hinzugekommen, den man auswählt. Dies führt dazu, dass im Wizard eine weitere Seite verfügbar ist, auf der Details für das Manifest angegeben werden können. Das Manifest selbst befindet sich im META-INF Verzeichnis des Web-Ordners, also eine Hierarchiestufe tiefer als in herkömmlichen OSGI Bundles.

Um das Web-Projekt testen zu können, ist zumindest ein Servlet nötig, welches in der web.xml definiert wird:

  <servlet>
<servlet-name>hello</servlet-name>
<servlet-class>test.TestServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

Das Servlet selber erbt von der Klasse javax.servlet.http.HttpServlet und überschreibt die doGet-Methode.

Sofern nicht bereits eine passende Target-Platform definiert wurde, wird es spätestens bei der Implementierung des Servlet zu einem Compile-Fehler kommen, da javax.servlet nicht aufgelöst werden kann. Zur Ausführung des Web-Projektes mit dem OSGI-Framework kann die Target-Platform von http://wiki.eclipse.org/Gemini/Web verwendet werden.

Bei Gemini selbst, handelt es sich um modulare Enterprise-Technologien, welche speziell für das OSGI-Framework konzipiert wurden.

Für die Installation werden folgende Archive benötigt: http://www.eclipse.org/downloads/download.php?file=/equinox/drops/R-3.7.1-201109091335/org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar und http://www.eclipse.org/downloads/download.php?file=/gemini.web/release/GW/2.0.1.RELEASE/gemini-web-2.0.1.RELEASE.zip.

Anschließend wird gemini-web in ein beliebiges Verzeichnis entpackt und org.eclipse.osgi.jar in eben dieses kopiert. Nun wird hier noch das Verzeichnis configuration erstellt und die folgenden beiden Konfigurationsdateien hinein kopiert:

http://wiki.eclipse.org/images/0/0b/Config.ini.2.0.1.zip

http://wiki.eclipse.org/images/3/32/Java6-server.profile.zip

Jetzt wird in Eclipse eine neue Target-Platform (Window / Preferences / Target Platform) erstellt, deren Location auf das gemini-web Verzeichnis verweist.

Als nächstes wird eine neue Run-Configuration unter dem Punkt OSGI Framework erstellt. Unter den VM-Arguments wird folgender Parameter hinzugefügt:

-Dosgi.java.profile=file:configuration/java6-server.profile

Außerdem muss als Working directory das gemini-web Verzeichnis angegeben werden.

Weitere Schritte sind nicht nötig, nun kann die Run-Configuration ausgeführt werden und die Web Applikation ist unter http:127.0.0.1:8080/<application-name>/hello verfügbar. Der Applikations-Name wird hier standardmäßig genommen, will man dies ändern, so ist der Parameter Web-ContextPath im Manifest anzupassen.

Die Facets von Eclipse Libra lassen sich nicht nur in WTP-Projekten nutzen. Es ist durchaus möglich, dieses Facet z.B. einem Maven-Projekt zuzuweisen, um hier die PDE Funktionalitäten nutzen zu können. Der Nachteil zu Apache-Felix ist hierbei allerdings, dass die pom.xml und das Manifest separat gepflegt werden müssen. Werden also Maven-Dependendies hinzugefügt, müssen diese auch im Manifest eingetragen werden, damit die Abhängigkeiten zur Laufzeit verwendbar sind.