CDI für Rich Clients

Erste Versuche

Ausgehend vom Java SE Sample von OpenWebBeans versuchten wir nach Hinzufügen der notwendigen Bibliotheken und der beans.xml-Datei, den Container im Plug-in-Activator zu starten bzw. zu stoppen. Leider stellte sich schnell heraus, dass OWB mit den Standardeinstellungen nicht gut mit Eclipse RCP zurechtkam. Ausgehend von einer NullPointerException in Scannotation, dem standardmäßigen Annotation-Scanner von OWB, war schnell klar, dass OSGi hier Probleme macht. Das Problem war, dass Scannotation nur file://- URIs, die direkt auf Dateien bzw. auf Jar-Archive verweisen, erlaubt. In einer OSGi-Umgebung werden diese Ressourcen allerdings mit bundle:// adressiert. Erfreulicherweise bietet OpenWebBeans ein eigenes OSGi-Plug-in an, das einen erweiterten Scannerservice für OSGi-Umgebungen auf Basis von Apache Geronimo XBean [4] bereitstellt. Leider traten auch hier Probleme auf, die auf die unterschiedlichen OSGi-Implementierungen von Eclipse und XBean zurückzuführen sind. Schließlich konnten wir aber mithilfe kleinerer Anpassungen des OSGi-Scannerservices den EclipseOsgiScannerService erstellen und OpenWebBeans zum ersten Mal erfolgreich starten. Um unseren eigenen Scannerservice zu verwenden, war dazu ein Eintrag mit dem Schlüssel org.apache.webbeans.spi.ScannerService in die Konfigurationsdatei META-INF/openwebbeans/openwebbeans.properties notwendig.

Wer erstellt die Instanzen?

Nun standen wir aber schon vor dem nächsten Problem: Damit die Dependency Injection auch funktionieren kann, müssen die Klasseninstanzen direkt von OpenWebBeans erstellt werden; Eclipse RCP erstellt jedoch alle seine Instanzen aufgrund der Extension-Point-Informationen in plugin.xml selbst. Listing 1 zeigt einen typischen Extension-Point-Eintrag in plugin.xml.

Listing 1

Wird nun der Editor mit der ID „at.ticketline.editor.artist“ aufgerufen, so erstellt Eclipse RCP eine Instanz der Klasse at.ticketline.kassa.ui.editor.ArtistEditor und verwendet diese. Wie sich aber durch Nachforschen in der Dokumentation von Eclipse herausstellte, werden im class-Attribut nicht nur die direkten Klassennamen, sondern auch so genannte Extension Factories unterstützt. Eine Extension Factory muss das Interface IExecutableExtensionFactory implementieren, das in der API-Dokumentation wie folgt beschrieben ist: „This interface allows extension providers to control how the instances provided to extension-points are being created by referring to the factory instead of referring to a class. [.] Effectively, factories give full control over the create executable extension process.“ Damit hatten wir jetzt eine Möglichkeit, in den Instanziierungsprozess von Eclipse RCP einzugreifen. Wie sich außerdem herausstellte, ist es möglich, gleichzeitig das Interface IExecutableExtension zu implementieren, um auch noch Zugriff auf alle Extension-Point-Attribute (wie z. B. die ID) aus plugin.xml zu bekommen. Damit war es uns möglich, eine eigene Extension Factory für OpenWebBeans zu erstellen.

CdiExtensionFactory und @EclipseExtension

Wir erstellten die Klasse CdiExtensionFactory, die das OpenWebBeans API verwendet, um Instanzen zu erzeugen und um somit in diesen Instanzen Dependency Injection zu aktivieren. Allerdings benötigten wir noch eine Möglichkeit, unserer Extension Factory mitzuteilen, welche Klasse sie für welchen Extension Point instanziieren sollte. Da wir durch Implementieren von IExecutableExtension die eindeutige Extension-Point ID zur Verfügung hatten, wollten wir die zugehörige Klasse zu einem Extension-Point mithilfe dieser ID identifizieren. Deswegen entschieden wir uns, den CDI-Qualifier @EclipseExtension zu erstellen. Ein Qualifier in CDI ist eine Annotation, die eine CDI-Bean genauer spezifiziert; beispielsweise können dadurch zwei unterschiedliche Implementierungen eines Service-Interfaces unterschieden werden (z. B. eine User- und eine Admin-Implementierung des gleichen Services). Qualifier können dabei auch verschiedene Attribute haben, die zur weiteren Spezifizierung einer CDI-Bean verwendet werden können. Wir verwendeten bei unserem Qualifier ein Attribut, das die Extension-Point ID beinhalten muss. Listing 2 zeigt den Qualifier @EclipseExtension.

Listing 2
/**
 * Qualifier identifying an Eclipse RCP extension point. 
 * @author Jakob Korherr
 */
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface EclipseExtension {

  /**
   * The id of the extension point. 
   * @return
   */
  String value();
}
Kommentare

Schreibe einen Kommentar

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