Applikationsdesign im Zeitalter von OSGi - JAXenter

Applikationsdesign im Zeitalter von OSGi

Das prominente, auf Bertrand Meyer zurückgehende Open Closed Principle [Robert C. Martin: The Open-Closed Principle, in: C++ Report 01, 1996] beschreibt die allgemeine Forderung an einen Entwurf, offen zu sein für Erweiterungen, aber geschlossen für Änderungen. Neue Funktionalität soll hinzugefügt werden können, ohne dass das Bestehende dafür modifiziert werden muss. Dieses Prinzip sollte von einem objektorientierten Entwurf unabhängig von OSGi berücksichtigt werden. Ein Softwaresystem, das neben dem Modulsystem und dem Abhängigkeitsmanagement aber auch auf die dynamischen Aspekte von OSGi setzt, kann dieses Prinzip sogar zur Laufzeit umsetzen. In Eclipse beispielsweise ist die Erweiterbarkeit des Systems (Stichwort „Plug-ins“) von Beginn an das herausstechende Qualitätsmerkmal gewesen, der Umstieg auf OSGi erhöhte in erster Linie die Dynamik. Grundsätzlich unterscheidet man in der OSGi-Welt zwei Ansätze, um dynamische Erweiterbarkeit zu erreichen: Das Service- und das Extension-Modell.

Service oder Extension?

Beim Servicemodell wird ein beliebiges Interface als Erweiterungspunkt definiert (Servicedefinition). Ein Bundle, das eine Implementierung der Schnittstelle beisteuern will, erzeugt und registriert ein Exemplar unter Angabe dieser Schnittstelle – in der Regel beim Start des Bundles. Komponenten, die an diesem Service interessiert sind, registrieren sich als Service Listener (direkt oder unter Verwendung des Service Trackers). Dieser Ansatz ist exakt die Form, wie OSGi ursprünglich gedacht war – SOA in der VM. Er entkoppelt Bundles voneinander und bietet eine hohe Dynamik. Der Lifecycle ist leicht nachvollziehbar und die Implementierung sehr einfach. Als Nachteil kann ins Feld geführt werden, dass Services auch erzeugt werden, wenn sie niemand benötigt. Dies führt bei Systemen mit vielen Bundles und Services zu längeren Startzeiten und verschwendet Ressourcen.

Das Extension-Modell ist in der Regel etwas aufwändiger umzusetzen, da ein eigener Rahmen dafür geschaffen werden muss. Die Idee besteht wiederum darin, Interfaces (oder Oberklassen, oder hier auch Datenstrukturen) als Erweiterungspunkte zu definieren, aber als Konsument nicht auf das Registrieren von Services zu lauschen (ServiceListener), sondern auf den Lebenszyklus von Bundles (BundleListener). Beim Hinzufügen in das Framework werden Metadaten des Bundles programmatisch ausgelesen und z.B. im Manifest nach bestimmten Headern gesucht, die etwa den Namen der Implementierungsklasse führen. Bei Bedarf wird von dieser dann per Reflection ein Exemplar erzeugt – das muss nicht zwingend bereits beim Installieren oder Starten des Bundles erfolgen. Weiterhin ist das Modell auch nicht auf Java-Klassen beschränkt; Bundles oder auch Bundle-Fragmente können zum Beispiel auch nur Ressourcen beisteuern, die einer bestimmten Datenstruktur entsprechen (z.B. Hilfetexte).

Die Felix-Dokumentation enthält als Beispiel ein einfaches Malprogramm, das im laufenden Betrieb um neue Figurenformen erweitert werden kann (Abb. 1). Die gleiche Anwendung wird sowohl in einer Service- als auch in einer Extension-basierten Variante implementiert; das Beispiel erlaubt so einen direkten Vergleich. Generell haben beide Modelle ihre Stärken und Schwächen, und es hängt von den konkreten Anforderungen ab, welches Muster angemessener ist. Im Zweifelsfall würde ich der Einfachheit halber den servicebasierten Ansatz wählen. Wichtig ist auf jeden Fall, diese Entscheidung bewusst zu treffen. Sie ist im Nachhinein nur sehr schwer zu revidieren. Eclipse hat sich für ein Extension-Modell entschieden.

Abb. 1: Das Felix-Beispiel zu Erweiterungsmodellen im Betrieb
Kommentare

Schreibe einen Kommentar

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