Erste Schritte mit OSGi – Teil II

Der Provider

Zunächst erstellen wir das Bundle com.weiglewilczek.example.osgi.hello.provider. Wir werden in der kommenden Folge auf übliche Namenskonventionen eingehen und bitten an dieser Stelle um Verständnis für die teils länglichen Namen. PDE unterstützt die Entwicklung von OSGi Bundles unter anderem durch Plug-in-Projekte. Diese sind, vereinfacht dargestellt, Java-Projekte, deren Build-Klassenpfad den deklarierten Abhängigkeiten der Bundles entspricht. Auf diese Weise können Laufzeitfehler aufgrund fehlender oder fehlerhaft deklarierter Abhängigkeiten schon zur Entwicklungszeit vermieden werden.

Abb. 5: New Plug-in Project Wizard

Plug-in-Projekte werden mit einem eigenen New-Wizard angelegt (Abb. 5). In unserem Beispiel wird auf der ersten Wizard-Seite com.weiglewilczek.example.osgi.hello.provider als Projektname eingetragen und an OSGi framework mit Ausprägung standard selektiert.

Abb. 6: New Plug-in Project Wizard II

Auf der zweiten Wizard-Seite können die Vorbelegungen mit einer Ausnahme übernommen werden: Dem vorgeschlagenen Namen für Activator wird ein internal-Package-Segment vor dem Klassennamen eingeschoben (Abb. 6).

Nach Fertigstellung wurde ein neues Projekt angelegt, das im Wesentlichen die Activator-Klasse sowie das Bundle Manifest (mehr dazu in der kommenden Folge) enthält.

Als Nächstes erstellen wir im Package com.weiglewilczek.example.osgi.hello.provider (diesmal ohne internal) das Service Interface IHelloProvider mit der Methode sayHello():

public interface IHelloProvider {
    String sayHello();
}

Dazu implementieren wir im Package com.weiglewilczek.example.osgi.hello.internal.provider (diesmal wieder mit internal) die Klasse OsgiHelloProvider:

public class OsgiHelloProvider implements IHelloProvider {
    public String sayHello() {
        return "Hello world!";
    }
}

In der Methode Activator.start() erzeugen wir eine Instanz des OsgiHelloProviders und registrieren diese als OSGi Service unter dem Serviceinterface IHelloProvider:

public void start(final BundleContext context) {
    context.registerService(
        IHelloProvider.class.getName(),
        new OsgiHelloProvider(), null);
}

Abb. 7: Deklaration der öffentlichen Schnittstelle

Abschließend deklarieren wir noch das Package, das das Serviceinterface als Bestandteil der öffentlichen Schnittstelle enthält. Dies erfolgt im Bundle Manifest, das wir durch Doppelklick im Package Explorer mit dem Manifest-Editor – einem weiteren PDE-Werkzeug – öffnen. Im Reiter Runtime fügen wir das Package com.weiglewilczek.example.osgi.hello.provider zu den Exported Packages hinzu (Abb. 7).

Der Consumer

Nun erstellen wir das Bundle com.weiglewilczek.example.osgi.hello.consumer. Dazu gehen wir analog zum Provider vor. Der Consumer enthält mit dem Activator nur eine Klasse.

Listing 1
public class Activator implements BundleActivator {

    private ServiceTracker helloProviderTracker;

    public void start(final BundleContext context) {
        helloProviderTracker = new ServiceTracker(context, 
                IHelloProvider.class.getName(), 
                new ServiceTrackerCustomizer() {

            public Object addingService(final ServiceReference reference) {
                final IHelloProvider helloProvider = (IHelloProvider) 
                        context.getService(reference);
                System.out.println(helloProvider.sayHello());
                return helloProvider;
            }

            public void modifiedService(final ServiceReference reference,
                    final Object service) { // Nothing to be done!
            }

            public void removedService(final ServiceReference reference,
                    final Object service) { // Nothing to be done!
            }
        });
        helloProviderTracker.open();
    }

    public void stop(final BundleContext context) {
        if (helloProviderTracker != null) helloProviderTracker.close();
    }
}

Listing 1 zeigt, wie wir in dessen Methode start() einen ServiceTracker (mehr dazu in kommenden Folgen) für obiges Serviceinterface anlegen. Der ServiceTrackerCustomizer ruft in der Methode addingService() den vom Provider registrierten IHelloService auf und gibt das Ergebnis auf der Konsole aus.

Abb. 8: Deklaration der Abhängigkeiten

Um den ServiceTracker und das vom Provider angebotene Serviceinterface nutzen zu können, müssen diese Abhängigkeiten im Bundle Manifest eingetragen werden. Dazu verwenden wir wiederum den Manifest-Editor und fügen im Reiter Dependencies die entsprechenden Packages hinzu.

„Hello World!“ in Aktion

Um dieses Beispiel ablaufen zu lassen, können wir eine weitere hilfreiche Funktion des PDE nutzen: Es ist nicht nötig, Bundles im korrekten Zielformat zu erstellen und in einem OSGi Framework zu installieren. Vielmehr können Plug-in-Projekte direkt aus der Entwicklungsumgebung heraus gestartet werden. Dazu wird eine Run Configuration vom Typ OSGi Framework benötigt.

Abb. 9: OSGi Framework Run Configuration

Über das Menü RUN | RUN CONFIGURATIONS … gelangen wir in einen Dialog, in dem wir eine neue OSGi Framework Run Configuration anlegen (Abb. 10). Dabei ist der Reiter Bundles besonders wichtig, denn hier legen wir fest, welche Bundles verwendet werden sollen. Die Voreinstellungen bewirken, dass die verwendeten Bundles nicht nur installiert, sondern auch gleich gestartet werden, was wir für unser Beispiel auch benötigen. Wir wählen unsere beiden Beispiel-Bundles und lassen mittels Add Required Bundles alle abhängigen Bundles automatisch ergänzen. Ein Klick auf RUN lässt uns „Hello World!“ in Aktion erleben (Abb. 9).

Schlussbemerkung und Ausblick

In dieser ersten Folge hatten wir einen Überblick über OSGi gegeben, die Architektur des OSGi Frameworks betrachtet und Modularisierung, Laufzeitdynamik und Serviceorientierung als wesentliche Eigenschaften von OSGi herausgestellt. Nun haben wir ein einfaches „Hello World!“-Beispiel mithilfe des Eclipse SDK entwickelt. Dabei wurde an der einen oder anderen Stelle bereits ein wenig auf kommende Folgen vorgegriffen. Die nächste Folge steht unter dem Motto „Immer in Bewegung – Bundles und Lifecycle“ und beleuchtet im Detail das Modulkonzept und die Laufzeitdynamik von OSGi.

Heiko Seeberger ist als Technical Director für die Weigle Wilczek GmbH tätig. Sein technischer Schwerpunkt liegt in der Entwicklung von Unternehmensanwendungen mit OSGi, Eclipse RCP, Spring, AspectJ und Java EE. Seine Erfahrungen aus über zehn Jahren IT-Beratung und Softwareentwicklung fließen in die Eclipse Training Alliance ein. Zudem ist Heiko Seeberger aktiver Committer in Eclipse-Projekten, Autor zahlreicher Fachartikel und Redner auf einschlägigen Konferenzen.

Kommentare

Schreibe einen Kommentar

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