OSGi enRoute: Ein neues Framework für OSGi-Anwendungen

Peter Kriens
OSGi enRoute

© iStock / StudioM1

Als wir im Jahr 1998 mit den Arbeiten an den OSGi-Spezifikationen begannen, hatten wir die Gelegenheit, ein Weltklasseframework für kleine Netzwerkgateways zu schaffen – das aktuelle Raspberry Pi ist im Vergleich dazu extrem leistungsfähig. Heute, sechszehn Jahre später, ist OSGi die führende Modularitätslösung für Java-Anwendungen auf dem Markt. Es ist eine Technologie, die wir für unabdingbar für die Entwicklung anspruchsvoller Java-Anwendungen halten. Dennoch zeigen diverse Blogs, dass einige falsche Annahmen über OSGi im Umlauf sind.

OSGi ist die einzige Lösung auf dem Markt, die die letzten Innovationen unserer IT-Industrie, etwa Objektorientierung und Inversion of Control/Dependency Injection, umfassend mit einschließt und darüber hinaus den nächsten Paradigmenwechsel mit sich bringt: serviceorientierte Programmierung. Dabei geht es nicht darum, auf einer Art Hypewelle mitzureiten – nein: Serviceorientierte Programmierung war keineswegs ein nachgelagerter Gedanke bei OSGi. Echte serviceorientierte Systeme (SOS) sind von Beginn an der Kern von OSGi gewesen. Erst nachdem die SOA-Bewegung den Begriff „Service“ für sich vereinnahmt hatte, begannen wir, unsere Services „Microservices“ zu nennen. Und mittlerweile verwenden wir den Begriff „μservice“, da „Microservice“ heute immer mehr für das weitaus schwergewichtigere Modell der REST-Services genutzt wird.

Obwohl das μservice-Modell das wichtigste Feature von OSGi ist, stellt es auch die größte Herausforderung für die Verbreitung von OSGi dar, weil es von Entwicklern fordert, anders zu denken. Java – und insbesondere Java EE – hat einige schlechte Angewohnheiten in Mode gebracht. Zum Beispiel war Class Loading niemals als Extensions-Mechanismus konzipiert. Und Statics in einem API haben dieselben Nachteile wie globale Variablen: Sie erzeugen beide unschöne Kontext- und Singleton-Probleme. Leider gibt es in Java kein mächtigeres Extensions-Modell, das die Entwicklung von Anwendungen aus wiederverwendbaren Modulen heraus erlaubt. OSGi liefert eine solche solide Lösung für Modularität.

Allerdings hat die Vermeidung der schlechten Angewohnheiten, die Java so antimodular machen, es OSGi erschwert, den Mainstream-Java-Entwickler zu erreichen. Nur wenn diese Entwickler sich so tief im Softwaredickicht verstricken, dass OSGi unvermeidbar wird, verstehen sie endlich die Lösungsansätze von OSGi.

Das OSGi-μservice- Modell ist ein Paradigmenwechsel

Das große Problem mit Paradigmenwechseln ist, dass das Publikum oft blind für die Vorteile des neuen Paradigmas ist. Das ist hervorragend im Buch „Flatland“ von Edwin A. Abbott nachgezeichnet, in dem es um das Leben in verschiedenen Dimensionen geht. Es wird gezeigt, wie ein Punkt, der in einer Welt von Linien existiert, sich niemals eine Ebene vorstellen kann. Genauso wird sich eine Ebene niemals eine Kugel denken könnte.

Und auch wir selbst sind verloren, wenn wir über eine vierte oder fünfte Dimension nachdenken. Wir verstehen sie zwar rational und haben keine Probleme damit, mit tausenden von Dimensionen zu rechnen – doch wir werden niemals etwas von einer Sache empfinden, die wir nicht wirklich erfahren haben.

Ein Beispiel: Im Sun Java Issue Tracker fragte einst jemand nach einer Multi Map – eine überraschende Lücke im Java Collections API. Der Issue wurde von Sun aber geschlossen, weil der Autor niemals die Notwendigkeit einer Multi Map verspürte – anders als die vielen nicht beachteten Upvoter. In ähnlicher Weise war es für mich als alter Smalltalker interessant, in den letzten Jahren die Diskussionen über die Einführung von Lambda-Ausdrücken in Java zu verfolgen. Viele Entwickler waren skeptisch. Doch werden dieselben Entwickler sich in einigen Jahren eine Welt ohne Lambdas nicht mehr vorstellen können. Die Welt wäre ein ruhiger Ort, wenn wir nur über Technologien reden würden, mit denen wir selbst schmerzvolle Erfahrungen gemacht haben.

Wir haben bei der OSGi Alliance also diese wundervolle neue Dimension der Softwareentwicklung – doch zeigt es sich, dass sie nur schwer zu vermitteln ist. Nur wer die Vorteile wirklich am eigenen Leib erfahren hat, wird verärgert aufschauen und fragen, warum ihm das niemand früher gesagt hat. Diese Leute schreiben dann gewöhnlich den 1 023. falsch verstandenen „Hello World“-Blog. Für jemanden, der sich im vergangenen Jahrhundert für objektorientierte Technologien stark gemacht hat, ist das ein seltsam vertrautes Déjà-vu-Gefühl. Ja, es gab eine Zeit, als die Industrie Objekten gegenüber sehr skeptisch eingestellt war.

Was ist so besonders an OSGi?

Für das bessere Verständnis machen wir eine kleine Tour durch unsere jüngste Geschichte. Wenn man in OSGi eine Komponente erzeugt, erhält man eine Klasse, die als μservice agiert und ihre Abhängigkeiten als μservices ausdrückt. Beispielsweise zeigt der Code in Listing 1 eine Komponente, die einen Speak μservice bereitstellt.
Listing 1

public interface Speak { void say(String text); }
@Component
public class SpeakLogImpl implements Speak {
  Logger logger;
  public void say(String text) {
    logger.info(text);
  }
  @Reference
  void setLog( Logger log) { this.logger = log; }
}

An dieser Stelle erfolgt üblicherweise der erste Angriff auf OSGi, denn wahrscheinlich ist die erste Reaktion: „Warum verwenden wir nicht @inject von CDI?“ Nun, das Problem mit neuen Dimensionen ist, dass so viel mehr dahintersteckt, als das Auge sehen kann. Erstens ist diese Komponente, obwohl hier nicht sichtbar, vollständig dynamisch und enthält viele Vor- und Nachgarantien für den Umgang mit Nebenläufigkeit. Beispielsweise wird der Speak-Service erst registriert, nachdem der Logger-Service registriert ist.

Wer nutzt den Speak μservice und woher kommt der Logger? Das ist irrelevant für die Komponente, die wir soeben erzeugt haben. Die Komponente hat seine Fähigkeiten ausgedrückt (den Speak μservice), die bereitgestellt werden, wenn seine Anforderungen (der Logger Service) erfüllt werden. Es ist die Aufgabe des Deployers, eine Umgebung zu schaffen, in der Anforderungen und Fähigkeiten miteinander korrelieren. Da die Komponente selbst diese Details nicht kennt, kann und sollte sie sich nur auf ihre Domänenfunktion fokussieren (die in unserem Beispiel ja recht trivial ist).

In diesem Beispiel können wir die dynamischen Elemente ignorieren, weil das System eine SpeakLogImpl-Instanz aktivieren wird, sobald die Abhängigkeiten erfüllt werden, und wieder deaktivieren, wenn die Abhängigkeiten verschwunden sind. Die Instanz ist sich dieses Lebenszyklus nicht wirklich bewusst, verhält sich aber in einer dynamischen Welt korrekt. Das ist so, als würde man aus einem Glas trinken, das immer voll bleibt.

Die Tatsache, dass das Ganze dynamisch abläuft, schreckt manche ab. Aber das ist so, als hätte man Angst, in einer dreidimensionalen Welt zu leben. Die Dinge ändern sich in der realen Welt, und wir tendieren dazu, diese dynamischen Veränderungen ohne domänenspezifischen Code zu verarbeiten. Mit der μservice-Primitive verfügen wir über eine wunderbar generische Grundlage, die eine überraschend hohe Anzahl an Aufgaben – Lebenszyklen, Initialisierung, Ausführungsreihenfolge, Fehlerbehandlung, Veränderungsszenarien – (fast) ohne domänenspezifischen Code verwaltet. Das Ergebnis ist, dass ein μservice-basierendes System typischerweise sehr robust und verlässlich ist.

Eines der besten Beispiele für die Nutzung der μservice-Dynamik sind verteilte Systeme. Da eine Komponente einen Service registriert, ohne vorzugeben, wer diesen Service nutzen kann, ist es für jede andere Komponente möglich, diese Registrierung zu beobachten. Abhängig von den Charakteristika des Service (und den jeweiligen Berechtigungseinstellungen) kann ein solcher Service deshalb als ein Kommunikationsendpunkt registriert und über eine Netzwerk-Service-Discovery-Schicht verfügbar gemacht werden. Ein anderes OSGi-System kann dann diesen Service aufnehmen und als lokalen Proxy μservice registrieren. Da Services dynamisch sind, funktioniert das auch weiterhin korrekt, wenn die Kommunikation abbricht oder der Provider des ursprünglichen Service entscheidet, den Service abzumelden – etwa, weil er gestoppt wurde oder seine Abhängigkeiten nicht mehr länger gegeben sind. Jeder, der schon einmal mit diesem Modell programmiert hat, hat es lieb gewonnen, ob seiner Eleganz und seiner Einfachheit bei der Verwaltung einer großen Bandbreite an Ausfallszenarien.

Der zweite Aspekt, der in unserem Beispiel nicht sichtbar ist, ist die Konfigurierung. Durch den OSGi Configuration Admin μservice ist es möglich, eine oder mehrere Instanzen des Speak-μservice zu definieren – alle mit unterschiedlichen Konfigurationseigenschaften, alles dynamisch und in Echtzeit.

Womöglich klingt das für Sie trivial (ich habe diese Reaktion oft erhalten, als ich den Leuten in den 80ern „Objekte“ erklärte). Aber ich kann versichern, dass die daraus resultierende Reduktion der Komplexität eines Systems sehr groß ist. Der Hauptgrund für die Komplexitätsreduktion ist die Wirkung, die das μservice-Modell auf das API dieser μservices hat. Da diese APIs sich nicht selbst mit dem Lebenszyklus, der Dynamik, Initialisierung, Konfiguration und tausend anderen Details, die nichts mit ihrer Domäne zu tun haben, beschäftigen müssen, sind sie üblicherweise viel, viel kleiner und einfacher.

Weil solche Probleme der Konfiguration und des Lebenszyklus wegfallen, müssen sich μservice-APIs in OSGi lediglich um die Zusammenarbeit untereinander kümmern. Wenn die Komponenten die Aktoren sind, dann sind die Services die Rolle(n), die sie spielen. Ein μservice-API beschreibt die Zusammenarbeit zwischen diesen Rollen, genauso wie das Drehbuch eines Films. Ein μservice-API ist deshalb nicht nur ein Interface, da wir im Allgemeinen mehrere Rollen, d. h. Interfaces, definieren müssen. Beispielsweise haben wir in der Event-Admin-μservice-Spezifikation die Rolle des Event Handlers und die Rolle des Event Admins.

Ein μservice-API ist daher in einem Java-Package spezifiziert. Dieses Package kann auch Hilfsklassen enthalten, etwa das Event-Objekt im Event Admin μservice. Ein gutes, in einem Package definiertes μservice-API ist sehr kompakt und nicht an andere APIs gekoppelt.

Die Komponenten müssen in einer Laufzeitumgebung deployt werden – das wird durch Bundles realisiert. Bundles enthalten alle Klassen, Ressourcen und Metadaten in einem JAR-File. Sie werden zur Laufzeit reifiziert. Das bedeutet, dass Komponenten nach Bundles suchen und diese basierend auf Informationen in diesem Bundle erweitern können. Zum Beispiel gibt es in OSGi enRoute den Web Server Extender, der Content des /static-Verzeichnisses eines Bundles auf den gegenwärtigen Webserver abbildet und zugleich die Cacheverwaltung und fortgeschrittene HTTP-Features wie (gecachete) Kompression und Ranges bietet. Dieses Muster wird das Extender-Modell genannt und ist eines der populärsten in OSGi.

Modularität

Bundles sind Module. Module funktionieren, weil sie eine Grenze definieren: Sie erzeugen einen privaten und einen öffentlichen Bereich. Dies reduziert Komplexität, weil es weniger veränderliche Teile gibt. Modularität ist ein anerkanntes Prinzip und wird allgemein recht häufig praktiziert. Der größte Unterschied zwischen OSGi-Modularität und traditionellem Java ist das Dependency-Modell. Wir haben von der Nutzung objektorientierter Technologien gelernt, dass es keine gute Idee ist, direkte Abhängigkeiten zu anderen Klassen einzubauen. Dies erzeugt Systeme, die einem Kaugummi im Haar gleichen: Alles klebt irgendwie miteinander zusammen. Die Innovation von Java bestand darin, dass es Interfaces einführte, um die transitiven Typenabhängigkeiten zu eliminieren, die so vielen objektorientierten Projekten in den 90ern zu schaffen machten. Interfaces lösen das Problem der transitiven Typenabhängigkeiten, weil beide, sowohl der Implementierer als auch der User, vom selben Interface, aber nicht mehr länger voneinander abhängen. Jetzt war es möglich, eine Library in einem anderen Kontext wiederzuverwenden, indem man lediglich das Interface implementierte, ohne andere User/Implementierer miteinzuschleppen.

Wenn Ihnen dieses Problem vage bekannt vorkommt, dann denken Sie wahrscheinlich an Maven. Maven nutzt genau dasselbe Identitäts-Dependency-Modell, das bei Klassen so spektakulär gescheitert ist. Wenngleich es stimmt, dass Maven nicht das ganze Internet herunterlädt – das tun schon die Leute selbst –, so ist es doch die Nutzung der direkten Modul-Identitäts-Dependencies mit Transitivität, die das Modell so gierig nach Downloads macht. Es wird hier ganz deutlich, dass wir für Module ein Äquivalent zu den Java-Interfaces brauchen: Was Java-Interfaces für Objekte dargestellt hat, benötigen wir auch für Module.

In OSGi hatten wir zunächst entschieden, das Package als das „Interface für Module“ zu nutzen, da es bereits die Einheit für das μservice-API war. Ein Bundle konnte deshalb ein Package exportieren (provide) und importieren (require). Wenn ein Bundle ein Package importierte, dann sollte ein anderes Bundle dieses Package exportieren. In diesem Modell konnte es viele Bundles geben, die dasselbe Package bereitstellen, was offensichtlich die Frage aufwirft: Wie finde ich die Bundles, die meine benötigten Packages exportieren?

Wenn man bei Maven ein Repository-URL, eine Gruppen-ID, eine Artefakt-ID und eine Version hat, kann man das Artefakt herunterladen. Allerdings ist man dabei auf diesen einen spezifischen Fall festgelegt, genauso wie die Nutzung einer Implementationsklasse in eine Sackgasse führt. In OSGi landet man hingegen nicht in einer Sackgasse, da Bundles in sehr unterschiedlichen Kontexten wiederverwendet werden können. Der Preis hierfür ist indes, dass vor dem Start ein zusätzlicher Assemblierungsschritt notwendig wird.

Über die Zeit lernten wir, dass Packages tatsächlich eine Instanz eines generischen Modells darstellen. Wir definieren jetzt alle unsere Abhängigkeiten in Bezug auf „Capabilities“ und erlauben auch userdefinierte Capabilities. Durch die semantische Versionierung dieser Capabilities können wir sicherstellen, dass wir auch Inkompatibilitäten auffinden. All das könnte Befürchtungen wecken, dass die Wartung dieser Capabilities viel Arbeit macht: Doch wir können Ihnen versichern, dass es Tools gibt, die das meiste direkt von den Klassendateien extrahieren. Es gibt sogar Annotationen, die die nötigen Metadaten generieren. Der Vorteil ist, dass Bundles jetzt selbstbeschreibend sind und wir Werkzeuge nutzen können, um Anwendungen aus Bundles zusammenzusetzen.

Schneller Vorlauf

In den letzten Jahren hat die OSGi Alliance ein solides Fundament für komponentenbasierte Systeme entwickelt, mit μservices als Schnittstelle zwischen den Komponenten. Bundles sind die Deployment-Einheiten. Sie sind selbstbeschreibend und können deshalb via Tools zu Anwendungen zusammengesetzt werden. Dieses Fundament ist tragfähig, weil die OSGi-Spezifikationen überraschend wenige Abkürzungen enthalten und extrem gut dokumentiert sind, um Interoperabilität zu ermöglichen. Es ist schwierig, sich eine bessere Grundlage für ein echtes Komponentenmodell für die Softwareentwicklung vorzustellen.

Andererseits haben wir gelernt, dass wir Anwendungsentwicklern bisher nicht genügend Aufmerksamkeit geschenkt haben. Unser Fokus lag bei den Implementierern der Spezifikation. Wir sagten den Anwendungsentwicklern im Grunde nur: Ihr habt nun eine fantastische Lego-Box zur Verfügung. Den Rest mussten sie dann selbst herausfinden. Und wenn sie dazu nicht imstande waren, war das ihr eigener Fehler.

Ein anderer Aspekt, den ich heute als Fehler ansehe, ist das API-Design einiger Services der OSGi-Enterprise-Spezifikationen. Die meisten dieser Spezifikationen wurden von den korrespondierenden Java-EE-APIs abgeleitet – oder sind gar identisch mit ihnen. Obwohl ich die Gründe hierfür verstehe – Java-EE-APIs verfügen über eine große Anhängerschaft und viele Implementierungen –, so denke ich doch, dass es ein Fehler war. Ein API wiederverwenden zu müssen, das für eine andere Welt konzipiert wurde, macht es sehr schwierig, die einzigartigen Möglichkeiten von OSGi zu nutzen.

Das Ergebnis ist eine Spezifikation, die zu stark vom Geist des „Das kann ich auch!“ geprägt ist, dabei aber der ursprünglichen Spezifikation hinterherhinkt und ärgerliche Abweichungen enthält – und darüber hinaus schon per Definition über weniger Implementierungen verfügt. Nichtsdestotrotz nutzen zahlreiche Unternehmen die Spezifikationen, und es ist immer herzerwärmend, von den überraschenden Orten zu hören, in denen die Technologie verwendet wird.

Wir glauben aber dennoch, dass es die Mühe wert ist, reine OSGi-APIs zu haben. In der Tat denken wir, dass die erhöhte Produktivität durch saubere APIs so hoch sein könnte, dass wir selbst Mainstreamentwickler überzeugen könnten, in unser Lager zu kommen, noch bevor sie vor dem Scheitern ihrer Anwendung stehen.

Das ist offensichtlich keine einfache Aufgabe, denn wer mit dem Mainstream konkurriert, steht oft auf verlorenem Posten. Ein großes Problem besteht darin, Implementierungen zu erhalten, da die meisten Open-Source-Projekte auf Java EE oder SE basieren. Glücklicherweise zeigt die Erfahrung, dass es aufgrund der Tatsache, dass OSGi-APIs meist viel kleiner sind, normalerweise nicht schwer ist, existierende (Open-Source-)Implementierungen zu nutzen, da eine überraschend große Anzahl der Implementierungsdetails verborgen bleibt.

Man packe nur einmal alle Klassen (und häufigen Abhängigkeiten) in ein Bundle und exportiere keine von ihnen, nur das kleine Collaboration-API. Das ist eines der Dinge, die nach einer steilen Lernkurve aussehen, die es zu meistern gilt. Doch in der Praxis ist es recht einfach, und man profitiert schnell von den Vorteilen von OSGi und seiner Modularität.

Warum OSGi enRoute

Der Wunsch nach echten OSGi-Services und das Bedürfnis, der Welt zu zeigen, wozu OSGi fähig ist, war der Grund für die OSGi Alliance, das Projekt „OSGi enRoute“ ins Leben zu rufen. Die Vision ist, eine Open-Source-Umgebung für OSGi-Anwendungen zu entwickeln, die 100 Prozent dem OSGi-Weg folgt: Das nutzen, was gut an OSGi ist, und das entwickeln, was in OSGi noch fehlt, wobei wo immer möglich mit existierenden Open-Source-Organisationen zusammengearbeitet werden soll.

Das OSGi-enRoute-Projekt versucht, alles aus einer Hand bereitzustellen: Best Practices, eine komplette Werkzeugkette, Profile, Dokumentation, Tutorials und eine Laufzeitdistribution. Mit OSGi enRoute lässt sich eine Webanwendung mit einem REST Backend in wenigen Minuten entwickeln und zum Laufen bringen (Ok, Downloadzeiten nicht einberechnet).

Was ist OSGi enRoute?

Die Werkzeugkette ist komplett. Sie besteht aus einer IDE (Bndtools basierend auf Eclipse), Continuous Integration (Gradle mit bnd) auf Travis, einer Integration mit GitHub und einem Repository namens JPM4J zur Indizierung von Maven-Central-Artefakten (und vieles mehr). Projekte, die in der IDE erzeugt werden, können auf GitHub gepusht werden, um dann automatisch ohne jeden Mehraufwand in Travis zusammengebaut zu werden.

Bndtools ist die zentrale OSGi-Entwicklungsumgebung. OSGi enRoute bietet ein grundlegendes Workspace-Template auf GitHub und Templates für die Erzeugung unterschiedlicher Projekttypen für APIs, Bereitsteller von APIs, Test-Bundles und Webanwendungen. Die Webanwendung erzeugt eine kleine Applikation, die ein Bootstrap-/Angular-User-Interface und ein REST Backend aufweist. Bndtools sorgt für sehr kurze Entwicklungszyklen zwischen einer Speicheroperation und zum Beispiel der Anzeige einer neuen Webseite, die die Modifikationen in einem JavaScript darstellt oder Anfragen an den Backend-REST-Server enthält. Das alles mit der notwendigen Genauigkeit.

Da die Werkzeugkette auf bnd basiert, werden Fehler und Bad Practices vor dem Release angezeigt. Bnd ermöglicht sogar Baselining, indem es ständig das aktuelle API mit dem vorherigen Release vergleicht und in Echtzeit semantische Versionsverstöße meldet. Und wenn man fertig für das Release ist, kann man entweder in verschiedene Repositories oder erst nach einem Continuous-Integration-Durchgang releasen. (Als Committer von bnd bin ich offensichtlich voreingenommen, aber ich habe noch keine andere Umgebung gesehen, in der es so einfach ist, OSGi und Java-Code zu entwickeln – und nicht nur das: Dasselbe gilt für JavaScript und andere Websprachen).

Ein OSGi-enRoute-Profil besteht aus einer Menge an Service-APIs, Extender und Webressourcen. Sie werden in einem JAR-File gesammelt, das nur eine Spezifikation ist. Dieses JAR-File kann dann im Build Path platziert werden und erlaubt es, Anwendungen ohne Anbieter-Lock-in zu entwickeln. Externe Abhängigkeiten können über das JPM Repository hinzugefügt werden. Derzeit umfasst das OSGi-enRoute-Base-Profil die folgenden Services:

  • osgi.service.cm – Stellt ein Push- und Pull-Modell zur Konfiguration von Komponenten bereit.
  • osgi.service.component – Ein Extender für Declarative-Services-Komponenten.
  • osgi.service.coordinator – Ein Koordinator für Thread-basierte Requests mit der Möglichkeit, einen Callback am Ende eines Requests zu erhalten.
  • osgi.service.event – Ein einfacher publish- und subscribe- Mechanismus für generische Events.
  • osgi.service.http – Ein HTTP-Serverframework.
  • osgi.service.log – Ein Service für das Logging von Fehlern, Warnungen und Informationen.
  • osgi.service.metatype – Ein Standard zur Beschreibung von Datenstrukturen mit der Absicht, User Interfaces daraus zu erzeugen.
  • osgi.service.url – Für die Registrierung von URL Handler über die Service Registry.
  • osgi.service.useradmin – Ein Service zur Verwaltung von Userinformationen wie Gruppen, Credentials und allgemeine Properties.
  • osgi.util.promise – Ein Tool für asynchrone Prozesse unter Verwendung von Promises.
  • osgi.util.tracker – Helfer für das zuverlässige Tracken von Services und Bundles.
  • enroute.authentication.api – Stellt eine authentifizierte ID auf der Basis variabler User Credentials bereit.
  • enroute.authorization.api – Autorisiert Anwendungen, ihre Aktionen auszuführen, indem aktuelle userbasierte Permissions genutzt werden.
  • enroute.capabilities – Alle spezifischen Non-Code Capabilities, die in einem enRoute-Base-Profil aufgefunden werden.
  • enroute.configurer.api – Ein Extender, der seine Konfigurationsinformation von einem Bundle erhält.
  • enroute.debug.api – Konstanten und Helfer für das Debugging.
  • enroute.dto.api – Unterstützung für die Konvertierung von Objekten auf andere Objekte oder JSON.
  • enroute.jsonrpc.api – Ein Whiteboard-Ansatz für JSON RPC.
  • enroute.launch.api – Ein API zur Interaktion mit dem Launcher, inklusive Zugang zu den Start-up-Argumenten.
  • enroute.logger.api – Für das Management von Logging auf einer Plattform, wenn nicht nur OSGi Logging verwendet wird.
  • enroute.rest.api – Stellt REST-Endpunkte bereit, die auf Method Naming Pattern basieren, inklusive typensicherer Nutzung von Payload, Parametern und Result Body.
  • enroute.scheduler.api – Stellt zeitbasierte Funktionen wie Delays (cron- und periodenbasiert), Schedules und Timeouts auf Promises zur Verfügung.

Die folgenden Webressourcen:

  • Angular JavaScript
  • Angular UI JavaScript
  • D3 JavaScript
  • Bootstrap CSS
  • Pagedown JavaScript Markdown Editor

Die folgenden Support-Bundles:

  • Ein Webserver, der statische Ressourcen von Bundles bereithält.
  • Ein Konfigurator, der Konfigurationen aus Bundles liest.
  • Ein OSGi Event Admin μservice für Server-sent Events (JavaScript) Bridge.

Das Base-Profil und seine Services basieren auf dem OSGi-Core-Release 6 und Java 8. Die neuen APIs nutzen ausgiebig Lambda-Ausdrücke.

Workflow

Das Profil ist ausreichend, um anspruchsvolle Webanwendungen zu bauen. In aktiver Entwicklung ist derzeit der Servicekatalog auf der enRoute-Webseite. Dieser Katalog stellt die derzeit noch fehlende Gebrauchsanleitung dar, wie ein Service zu nutzen ist. Es ist unsere Absicht, jedem Service eine exemplarische Anwendung zur Seite zu stellen, die es dem Entwickler erlaubt, das Anwendungsmuster zu kopieren und in einem Debugger mit dem Service zu spielen. Serviceorientierte Systeme setzen sich aus Bundles zusammen, die eine allgemeine Wiederverwendbarkeit anstreben. Selbst wenn die Wiederverwendbarkeit nicht immer gegeben ist, so ergibt es meist Sinn, Services so zu entwickeln, als wären sie potenziell wiederverwendbar. Das macht einem das Leben schon während der Entwicklungsphase leichter. Definiere saubere APIs und stelle sicher, dass nur API-Packages exportiert werden.

Nach der Entwicklung oder der Auswahl der Komponenten aus dem Repository müssen diese in eine Anwendung gepackt werden. In klassischen Umgebungen kann es schmerzvoll sein, eine solche Anwendung zu erzeugen, da sie alle transitiven Abhängigkeiten enthalten muss – und ohne Hilfe kann das recht mühselig sein. Deshalb verfügen die Bndtools über einen Auflösungsmechanismus, der helfen kann, schnell ein Paket von Bundles zu erzeugen, die alle notwendigen Capabilities enthalten. Wenn diese Applikation definiert ist, bietet Bndtools eine Debug- und Testumgebung, die sehr reaktionsfähig ist. Man erzeugt ein bndrun-File, das die Details wie das Framework und die Properties spezifiziert. Dieses bndrun-File kann dann gestartet und debuggt werden. Wirklich alle Änderungen in der IDE werden unmittelbar wiedergegeben; man muss nur selten das Framework neu starten.

Das Output Packaging hängt dann von der Zielumgebung ab. Derzeit paketieren wir per Default also ein ausführbares JAR, das das Framework, die Properties und alle Bundles enthält. Das JAR läuft überall, wo eine Java-8-Laufzeitumgebung verfügbar ist. Allerdings arbeiten wir derzeit mit IBM daran, es auch auf dem WebSphere Application Server Liberty Core zu deployen und zu debuggen. Ebenso strebt Paremus an, Deployments auf der Paremus Service Fabric zu ermöglichen. Darüber hinaus haben wir auch Karaf Kars und andere Umgebungen im Auge – jede weitere Zielumgebung ist mehr als willkommen.

Diese Zielumgebungen müssen eine Distribution bereitstellen, wobei eine Distribution wiederum jede Capability bieten muss, die im Profil definiert ist. Dokumentation und Tutorials (auf die derzeit der Fokus liegt) finden sich unter http://enroute.osgi.org. Zudem sind alle Arbeiten auf GitHub einzusehen. Allen, die die verschiedenen Teile ausprobieren möchten, bietet sich hier ein guter Startpunkt.

Wo stehen wir?

Stellt sich am Ende die Frage: Auf welchem Stand ist OSGi enRoute derzeit? Im Prinzip sind wir funktionskomplett und bereit für die Integrationstests. Das bedeutet, dass wir eifrige Early Adopter benötigen, die in der Lage sind, einige Ecken und Kanten auszuhalten und OSGi enRoute weiterzubringen. Das Releasedatum für die Version 1.0 ist auf diesen Sommer angesetzt, in Linie mit dem geplanten OSGi-Enterprise-Release 6, sodass etwaige Updates der Spezifikation mit einfließen können.

Das meiste der noch ausstehenden Arbeiten besteht nun im Schreiben der Dokumentation, dem Erstellen von Tutorials und dem Bekanntmachen von OSGi enRoute.

Fazit

Die Arbeiten an OSGi enRoute haben deutlich gemacht, dass wir der Welt eine wunderbar solide Lego-Box übergeben haben, ohne an die Bauanleitungen zu denken. Es ist klar, dass OSGi-Modularität wirklich funktioniert; es stellt ein anspruchsvolles Dependency-Modell bereit, mit dem man tatsächlich Anwendungen aus wiederverwendbaren Komponenten bauen kann. Es wurde aber auch klar, dass wir unbedingt reine OSGi-Services für die gängigen Aufgaben benötigen, mit denen jeder Entwickler konfrontiert ist. Wir haben bisher zu wenige davon gehabt. Jetzt schon haben die Arbeiten an OSGi enRoute zu zehn neuen OSGi Requests For Proposals geführt (OSGi RFP, der erste Schritt im Spezifizierungsprozess).

Wenn Sie also daran interessiert sind, einer der Early Adopter zu sein – oder wenn Sie Zeit haben, am Projekt mitzuarbeiten, zögern Sie nicht, mich zu kontaktieren. Für alle anderen: Halten Sie die Augen offen, denn wenn wir vollständig live sind, wird OSGi überwältigend sein!

Geschrieben von
Peter Kriens

Peter Kriens ist seit 1990 als unabhängiger Consultant tätig. Zurzeit arbeitet er für die OSGi Alliance und am Package Manager jpm4j (www.jpm4j.org). Während der Achtzigerjahre entwickelte er in der Zeitungsbranche fortgeschrittene verteilte Systeme mittels der zu dieser Zeit sehr neuen objektorientierten Technologien. Aufgrund dieser Erfahrung wurde er von zahlreichen internationalen Unternehmen engagiert, darunter Adobe, Intel, Ericsson und IBM. Während seiner Arbeit bei Ericsson Research 1998 wurde er in die Spezifizierung von OSGi involviert; später avancierte er zum hauptsächlichen Verfasser dieser Spezifikationen. 2005 wurde ihm der Titel OSGi Fellow verliehen. Nach seiner Auszeit im Jahr 2012, die er der Entwicklung von jpm4j widmete, kehrte er zur OSGi Alliance zurück, um die Verbreitung von OSGi zu fördern.

Kommentare

Hinterlasse einen Kommentar

avatar
4000
  Subscribe  
Benachrichtige mich zu: