08. Dezember 2016

synTechTalk: OSGI Advanced

synTechTalk: OSGI advanced - Bild: Lily http://www.freevector.com/jigsaw-puzzle (CC BY 4.0), synaix

Nach der Einführung in die Welt von OSGI gehen wir in diesem Beitrag einen Schritt weiter und beschäftigen uns mit einigen Tricks und Hilfsmitteln, mit denen wir die Services noch einfacher und besser gestalten können.

Alle hier vorgestellten Beispiele wurden auf dem Apache Servicemix getestet. Die Beispiele sollten auch in anderen Containern laufen, dafür sind ggf. einige kleinere Anpassungen notwendig. (Ein Hoch auf den Standard! ;-))

Funfact: Best Practice

Wenn man sich tiefergehend mit dem Standard beschäftigt und ein wenig recherchiert, stößt man auf einige Best Practices bezüglich OSGI. Doch nun kommt der absolute Geheimtipp: Wenn man mit OSGI arbeiten möchte, dann hält man sich am besten weit entfernt von den implementierten Klassen des Standards.

Uups! Wie kann es denn Best Practice sein, nicht mit OSGI zu arbeiten, wenn man mit OSGI arbeiten möchte?

Die Antwort ist eigentlich einfach und nachvollziehbar: Es ist ziemlich aufwendig, ein OSGI-Bundle zu erstellen. Diejenigen, die bereits ein paar Bundles händisch angelegt haben, werden es schon erfahren haben. Es schleichen sich leicht Fehler in der Manifest-Datei ein und jeder Fehler wird direkt mit einer Exception bestraft. Manchmal stimmen irgendwelche angegebenen Pfade zu der Activator-Klasse nicht oder irgendein Service wurde falsch geschrieben – und schon fliegt einem der ganze Spaß um die Ohren.

Um die Programmierung angenehmer zu gestalten, gibt es ein paar Hilfsmittel, die einem die direkte Arbeit mit dem Standard abnehmen und dabei sehr komfortabel sind. Zwei wirklich praktische Hilfsmittel stelle ich hier vor.

#1 Maven Bundle-Plugin

Das Maven Bundle-Plugin wird auch das „nie-wieder-probleme-mit-dieser-verdammten-manifestdatei“-Plugin genannt. Und es hält, was es verspricht.

Anstatt der gängigen Manifestdatei nutzen wir eine gute alte pom.xml. In der POM haben wir die gewohnten Abhängigkeiten und können sogar auf andere Bundles referenzieren. Das ist ziemlich praktisch, da damit die meisten IDEs auch wieder die Abhängigkeiten auflösen können und die ganzen unnötigen Fehlermeldungen verschwinden.

Aber das Wichtigste ist dabei der Bereich des Maven Bundle-Plugins. Hier kann man angeben, welche Packages im- und exportiert werden, welche Abhängigkeiten zwischen den Bundles bestehen und natürlich den eingesetzten Pfad zum Bundle-Activator.

Beim Bauen des Bundles erstellt Maven direkt die Manifestdatei für uns und wir haben keine Probleme mehr mit Typos etc.

Beispiel-POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.my.example</groupId>
    <artifactId>example-bundle</artifactId>
    <version>1.0.0</version>
    <packaging>bundle</packaging>

    <name>Example :: ${project.artifactId} (${project.version})</name>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>4.3.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>de.my.example</groupId>
            <artifactId>example-service</artifactId>
            <version>[1.0.0,1.1)</version>
            <type>jar</type>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.5.4</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-Activator>de.my.example.bundle.internal.Activator</Bundle-Activator>
                        <Import-Package>!de.my.example.bundle.*,*</Import-Package>
                        <Export-Package>de.my.example.bundle</Export-Package>
                        <Private-Package>de.my.example.bundle.*</Private-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

#2 Blue Print

Das Gemini Blue Print Projekt ähnelt den klassischen Spring-Beans, die wir aus den meisten Webprojekten kennen. Tatsächlich haben sich die Macher des Blueprint-Frameworks am Springframework orientiert.

Blueprints sind de Facto xml-Dokumente, in denen man Beans definieren kann. Das wirklich Praktische ist jedoch, dass man über die Blueprints auf die Service-Struktur der OSGI-Umgebung zugreifen kann. Das bedeutet, dass man Services registrieren und auslesen kann.

Beispiel-Blueprint:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

    <reference id="exampleService" interface="de.my.example.service.ExampleService" />
    
    <bean id="exampleBundle" class="de.my.example.bundle.internal.ExampleBundleImpl">
        <property name="exampleService" ref="exampleService"/>
    </bean>
    <service ref="exampleBundle" interface="de.my.example.bundle.ExampleBundle" />

</blueprint>

Wer tiefer in das Thema Blueprints einsteigen möchte, findet hier eine weitgehend vollständige Dokumentation: http://aries.apache.org/modules/blueprint.html

Zusätzlich bauen weitere Projekte auf dem Blueprint-Projekt auf bzw. sind über Blueprints konfigurierbar. Es ist zum Beispiel möglich, cxf und jaas über Blueprints anzusprechen. Das ganze ist dann jedoch ein wenig tricky. Um den Rahmen dieses Posts nicht zu sprengen, folgt dafür bei Interesse ein weiterer Post.

Mit diesen beiden Hilfsmitteln kann man sich schon ziemlich gut in der Welt von OSGI bewegen. Jedoch gibt auch hier ein paar Richtlinien, an die man sich halten sollte:

#1 Nano-Services

Ja es ist möglich, für Alles einen eigenen Service anzulegen. Das heißt jedoch nicht, dass man das auch machen sollte. Am Besten ist es, mehrere Funktionen in einem Service zu sammeln. Das erhöht die Übersichtlichkeit und ermöglicht es, dass auch andere Leute mit im Projekt arbeiten können – ohne vorher 1000 Interfaces auswendig lernen zu müssen.

#2 Trennung von Services

Umgekehrt ist es auch möglich, alle Funktionen in einem einzigen Service zu sammeln. Das ist jedoch auch nicht sinnvoll, denn dann können wir uns den ganzen OSGI-Standard sparen und nach wie vor monolithisch arbeiten. Jeder Service sollte für einen bestimmten Zweck bestehen, den auch genau dieser eine Service erfüllt. Ein Account-Service sollte Accounts verwalten und ein Bestell-Service sollte Bestellungen verwalten. So sorgt man dafür, dass die Gesamtstruktur nachvollziehbar ist.

#3 Doku

Fehlende Dokumentation hat zur Folge, dass andere Leute nicht wissen, welche Services implementiert wurden. Das führt dazu, dass vorhandene Services nicht verwendet werden oder sogar doppelt implementiert werden. Es gibt schönere Möglichkeiten, seine Zeit zu verbringen – also schreibt lieber direkt die zugehörige Doku!

So weit meine fortgeschrittenen Einblicke in OSGI. Bei Fragen und Anregungen stehe ich natürlich gern zur Verfügung und setze die Reihe über OSGI bei weiterem Interesse gerne fort.

(Olaf Matticzk)

In unserer Reihe synTechTalk geben unsere DEV und OPS Teams Einblicke in ihr Technologie- und Architektur- KnowHow zur Umsetzung erfolgreicher digitaler Geschäftsmodelle.

Keine Kommentare