home  |  suche  |  kontakt/johner  |  institut 
studierende  |  tech-docs  |  mindmailer 

OSGI Tutorial

OSGi steht für Open Service Gateway Initiative und ist eine Technologie, die ursprünglich für die Gebäudetechnik eingesetzt war. Dort besteht die Notwendigkeit, Anwendungsteile (Komponenten) hinzufügen, zu ändern und auch wieder entfernen zu können. Die Ihnen bekannteste Anwendung, die komplett auf OSGI basiert, ist Eclipse, das sehr konsequent das Plugin-Konzept umsetzt.

Eclipse verfügt über eine eigene Implementierung der OSGI API, die sich Equinox nennt. Weitere Implementierungen sind Apache Felix und Knopflerfish.

OSGI setzt drei Konzepte um:

  • Modularität (auch zur Laufzeit!): In Java gibt es kein Modulkonzept oberhalb der Package-Ebene. Jar-Dateien stellen per se keine Kapselung dar, denn sobald eine jar-Datei sich im Klassenpfad befindet kann man auf alle darin befindlichen Klassen zugreifen.

    Die OSGI-Module/Komponenten (werden Bundles genannt) liegen zwar ebenfalls als jar-Dateien vor, aber die Manifest-Datei dieser jar-Datei spezifiziert über „Export-Package“ (s.u.), welche Klasse/Interface OSGI-Frameworks nutzbar sein soll. Nur auf diese Klasse/Inteface können andere Bundles zugreifen.

    Damit sind die Bundles (Module/Komponenten) lose gekoppelt, so dass man von den Vorteilen der Modularität, nämlich Wartbarkeit, Austauschbarkeit, Testbarkeit, profitiert.
  • Laufzeitdynamik: Dank OSGI ist es möglich, Module während der Laufzeit auszutauschen (Hot-Deployment). Dabei berücksichtigt das OSGI-Framework die Abhängigkeiten der Bundles untereinander, die in den Manifest-Dateien definiert sind (über import-Statements). Das Framework kann mehrere Versionen eines Bundles parallel verwalten.
  • Serviceorientierung: Die einzelnen Bundles können als Dienste zur Verfügung gestellt werden. Die meisten OSGI-Implementierungen stellen bereits viele Dienste wie http, Logging oder Monitoring bereit.
    Zusätzlich zu dem Service Layer gibt es noch ein Security Layer, mit dem Bundles signiert oder der Zugriff darauf auf spezielle Bundles beschränkt werden kann.

Ein Bundle durchläuft wohldefinierte Zustandsübergänge: Initial liegt ein Bundle nur als jar-Datei vor. Sobald das Framework es zu installieren beginnt, geht es in den Zustand "installed" über. Sobald alle Abhängigkeiten zu anderen Bundles erfolgreich (!) aufgelöst sind, befindet sich das Bundle im Zustand "resolved". Der Befehl "start" überführt das Bundle in den Zustand "starting" der nach dem Starten automatisch in "active" übergeht. Es empfiehlt sich daher, aufwendige Aufgaben während des Startens in einen eigenen Thread auszulagern. Mit "stop" kehrt das Bundle wieder in den Zustand "resolved zurück", wo es mit "unsinstall" aus dem Framework entfernt wird. Ein "update", d.h. ein Neuladen des Bundles nach einer Änderung ist in den meisten Zuständen möglich.

Bundles

Bundles liegen als gepackte Java-Archive (jar-Dateien) vor, die ein Verzeichnis META-INF haben, das eine Manifest-Datei enthält. Beispiel für eine Manifest-Datei:

 

Manifest-Version: 1.0
Built-By: Christian Johner
Bundle-Name: Telefonbuch 2
Bundle-Description: Unser erstes Telefonbuch
Bundle-Vendor: HTWG Konstanz
Bundle-Version: 1.0.0
Bundle-Activator: telefonbuch.service2.TelefonbuchActivator2
Export-Package: telefonbuch.serviceinterface
Import-Package: org.osgi.framework

 

Die Datei ist weitgehend selbsterklärend.

  • Ein Beispiel für den Bundle-Activator, also die Klasse, die vom OSGI-Framework aufgerufen wird, wenn das Bundle gestartet oder gestoppt wird, Opens internal link in current windowfinden Sie hier.
  • Das Export-Package gibt die Klassen an, die für anderen Bundles sichtbar sein sollen. Wohlgemerkt: Das OSGI macht nur diese und nicht alle Klassen in der Jar-Datei zugänglich. Das Import-Package definiert die Abhängigkeiten zu anderen Packages. Diese Abhängigkeiten sollten möglichst gering sein.
  • Mehrere Packages bei Export oder Import werden durch Kommata getrennt. Bei diesen Packages lässt sich zudem eine bestimmte Version verlangen (z.B. Import-Package: de.meinpackage;version="1.0.0") oder ein Bereich an Versionen (z.B. Import-Package: de.meinpackage;version="[1.0.0,2.0.2)"), wobei die eckige Klammer für geschlossene und die runde Klammer für offene Intervallgrenzen stehen. Bitte beachten Sie auch, dass das Package und die version durch ein Semikolon getrennt sind.

Rezept

  1. Neues Projekt in Eclipse anlegen

    1. Output-Folder von bin auf classes ändern.

  2. Apache Felix herunterladen und in das Projekt hinein kopieren
    1. Neue Verzeichnisse bundle, bin, conf entstehen
    2. felix.jar (bin-Verzeichnis) zum Klassenpfad hinzufügen (siehe Abb.)
  3. Neue Run-Config  (siehe Abbildung unten)
    1. Main-Class: org.apache.felix.main.Main
    2. VM-Parameter setzen
    3. Felix starten
  4. Bundles entwickeln (Opens internal link in current windowsiehe Beispiel)
    1. Getrennte packages für Provider, Provider-Interface und Consumer
    2. Manifest-Dateien schreiben (siehe Beispiel oben) (Achtung: Manifest-Datei muss mit eine leeren Zeile abbrechen, also CR nach letztem "Statement")
    3. Als Jar exportieren (mit Eclipse -> Export -> Java -> Jar)
      1. rechte Mausklick auf jeweiliges Package (bei Provider inklusive Service-Interface-Package, also zwei Packages)
      2. Eigene Manifest hinzufügen

  5. Bundles installieren

    1. In Felix Konsole start file:meinjarfile.jar (es funktionieren keine Dateipfade mit Leerzeichen, aber start file:/c:/tutorial/example2.jar funktioniert)
    2. Weitere Befehle

      1. ps:  Auflisten der Bundles
      2. Stop <id>
      3. Uninstall <id>
      4. Update <id>
      5. Refresh (hilft manchmal!)

  6. Bundles updaten
    1. Klassen ändern
    2. jar-Datei neu erstellen
    3. update <id>  (Meldung des ServiceListeners folgt)
    4. update <id_client>  (neue Adresse wird angezeigt)