JM 02/09 - OSGi in kleinen Dosen 3

762 Aufrufe

Veröffentlicht am

Third article "OSGi in kleinen Dosen" in German Java Magazin 02/09.

Veröffentlicht in: Technologie, News & Politik
0 Kommentare
1 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
762
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
7
Aktionen
Geteilt
0
Downloads
36
Kommentare
0
Gefällt mir
1
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

JM 02/09 - OSGi in kleinen Dosen 3

  1. 1. Java Core OSGi in kleinen Dosen – Teil 3 Immer in Bewegung – Services à la OSGi Die OSGi Service Platform (OSGi) hat sich zu einem sehr bedeutenden Standard im Java-Umfeld entwickelt. Also wird es für den engagierten Java-Entwickler allerhöchste Zeit, sich damit näher auseinanderzusetzen. von Heiko Seeberger registrieren von Services zu reagieren. die Frage, wie man diese gestalten kann, achdem in der fün eiligen Se- Wie trägt nun das OSGi Service Model sodass die Vorteile der Modularisierung rie die technischen Grundlagen zur losen Kopplung bei? Zum einen ab- erhalten bleiben. Schließlich wäre nichts von OSGi sowie Modularisie- strahiert die Verwendung von Service gewonnen, wenn die Module quasi zu- rung und Laufzeitdynamik unter die Lu- Interfaces von der konkreten Imple- sammengeschweißt würden, sodass sie pe genommen wurden, geht es diesmal mentierung, sodass die Anbieter von untrennbar miteinander verbunden im Detail um das OSGi Service Model, Services austauschbar sind. Zum ande- sind. Es gilt also, die Architektur und der dritten wesentlichen Eigenschaft ren ermöglicht die Indirektion durch die das Design so zu wählen, dass eine lose von OSGi. Service Registry, dass Services genutzt Kopplung der Module erzielt wird. Services und lose Kopplung werden können, ohne dass das nutzende OSGi beantwortet diese Frage mit Bundle mit deren Erzeugung zu tun hät- dem OSGi Service Model (Abb. 1). Das Im letzten Artikel haben wir Modulari- te und somit unabhängig von konkreten OSGi Framework stellt eine Service Re- sierung als ein Mittel zur Reduktion von Anbietern bleibt. gistry zur Verfügung, an der Bundles Komplexität und letztendlich zur Steige- Services registrieren können. Dabei sind rung von Produktivität, Flexibilität und Beispiel und Entwicklungs- Services Instanzen gewöhnlicher Klas- Qualität in der So wareentwicklung ge- umgebung sen, also POJOs (Plain Old Java Objects). priesen. Allerdings bestehen die Lösun- Zur Registrierung dient das Service In- gen für die Herausforderungen, mit de- Wir erweitern heute das Beispiel des terface, ein „gewöhnlicher“ Java-Typ, nen man sich in der Praxis konfrontiert „universellen Adressbuchs“ aus dem in der Regel ein Interface. Dieses wird sieht, in der Regel aus mehreren oder letzten Artikel um die Verwendung von ebenso verwendet, um Services von der gar zahlreichen Modulen. Diese müs- OSGi Services. Dazu wird das bereits existierende Bundle com.weiglewilczek. Service Registry zu erfragen. Um der sen miteinander kollaborieren, sodass example.osgi.contacts.inmemory Ser- OSGi-Dynamik Rechnung zu tragen, nach der Zerlegung in überschaubare gibt es in Form von ServiceListeners die Häppchen wieder die Zusammenfüh- vices registrieren und das neue Bundle com.weiglewilczek.example.osgi.con- Möglichkeit, auf Registrieren oder De- rung ansteht. Dabei stellt sich natürlich tacts.shell diese nutzen. Um Gerechtig- keit walten zu lassen, wird diesmal – wie Artikelserie: OSGi in kleinen Dosen schon beim „Hello World!“-Beispiel im ersten Teil – Eclipse Equinox und PDE Teil 1: Erste Schritte mit OSGi eingesetzt, nachdem wir das letzte Mal Teil 2: Immer in Bewegung – Bundles und Life Cycle die Verwendung von Apache Felix und Teil 3: Immer in Bewegung – Services à la OSGi Quellcode Bnd gezeigt haben. Für dieses Beispiel Teil 4: Alles XML oder was? – Services auf deklarative Weise auf CD benötigt man eine aktuelle Version (3.4.1 Teil 5: Hier wird „Service“ groß geschrieben – Ausgewählte OSGi- zum Zeitpunkt der Erstellung dieses Ar- Standardservices tikels) des Eclipse SDK mit PDE, z. B. das 14 javamagazin 2|2009 www.JAXenter.de
  2. 2. Java Core Abb. 1: OSGi Service Model Abb. 2: OSGi- Filtersyntax Anzeige zwei InMemoryContactRepositories mit Package „Eclipse for RCP/Plug-in Devel- Spieldaten und registrieren diese unter opers“ [1]. Den kompletten Sourcecode dem Service Interface ContactReposito- des Beispiels nden Sie auf der Begleit- ry (Listing 1). CD oder als Download [2]. Optional können Service Properties Services registrieren in Form von Schlüssel-Wert-Paaren ge- setzt werden. Dabei müssen die Schlüssel Wie bereits erwähnt, werden Services an Strings und die Werte primitive Typen der Service Registry des OSGi Frame- oder solche aus java.* sein, um implizi- works registriert. Wie die gesamte In- teraktion mit dem OSGi Framework, ge- te Abhängigkeiten zwischen Bundles zu schieht auch dies mithilfe des Interfaces vermeiden. In unserem Beispiel setzen wir die Service Property contactReposi- BundleContext. Die wichtigsten Metho- tory.name, deren Wert einen Namen für den hierfür lauten: einen ContentRepository Service reprä- ServiceRegistration registerService(String clazz, sentiert. Object service, Das OSGi Framework vergibt ana- Dictionary properties); log zu Bundles für jeden Service eine ServiceRegistration registerService(String[] clazz, eindeutige numerische ID und setzt die- Object service, se als Wert der Service Property service. Dictionary properties); id. Die Service Interfaces, unter denen Der erste Parameter ist der voll quali - ein Service registriert wird, werden vom zierte Name des Service Interfaces bzw. OSGi Framework als Wert der Service Property objectClass (Tabelle 1) abge- mehrerer Service Interfaces. Dabei ist wichtig, dass der Service, der im zweiten legt. Parameter übergeben wird, das Service Damit kommen wir zum Lebens- Interface bzw. alle Service Interfaces zyklus von Services, der eng mit dem implementiert. Andernfalls werden von Bundles verknüp ist. Nur wenn diese Methoden eine IllegalArgument- sich ein Bundle im Zustand S , Exception werfen. In unserem Beispiel A oder S be ndet, kön- erzeugen wir im Bundle com.weiglewil- nen über dessen BundleContext Servi- czek.example.osgi.contacts.inmemory ces registriert werden. Typischerweise javamagazin 2|2009 15 www.JAXenter.de
  3. 3. Java Core OSGi in kleinen Dosen – Teil 3 dessen Property service.ranking (Tabel- geschieht das beim Starten, d. h. in der Methode BundleActivator.start(). Mit- le 1) den höchsten Wert hat. Falls dies zu keiner eindeutigen Entscheidung hilfe der beim Registrieren zurückge- gebenen ServiceRegistration können führt, wird der Service mit der kleins- Listing 1 ten ID verwendet. Services wieder deregistriert werden. // First service In unserem Beispiel erstellen wir Allerdings ist das „manuelle“ Dere- Hashtable<String, Object> properties = new Hashtable<String, Object>(); ein neues Bundle com.weiglewilczek. gistrieren o gar nicht nötig, weil das properties.put(ContactRepository.NAME, “In-memory“); example.osgi.contacts.shell, das beim OSGi Framework dies automatisch Contact[] contacts = new Contact[] { Starten alle registrierten ContactRe- vornimmt, wenn ein Bundle gestoppt new Contact(“John“, “Doe“), pository Services aufruft, sodass wir wird. new Contact(“Max“, “Mustermann“) }; context.registerService(ContactRepository.class.getName(), getServiceReferences() verwenden. Services nutzen new InMemoryContactRepository(contacts), properties); Beide Methoden bedürfen der Prüfung auf null, denn dies ist der Rückgabe- Zur Nutzung von Services sind zwei // Second service wert, auch für getServiceReferences(), Schritte erforderlich. Zunächst wird un- properties = new Hashtable<String, Object>(); falls kein Service zur Anfrage passt. ter Angabe eines Service Interfaces eine properties.put(Constants.SERVICE_RANKING, 1); Anschließend kann getService() auf- oder mehrere ServiceReferences erfragt, properties.put(ContactRepository.NAME, “In-memory-2“); gerufen werden, wobei eine zuvor zu- danach werden mithilfe dieser der oder contacts = new Contact[] { new Contact(“Another“, “One“) }; rückgelieferte ServiceReference als Pa- die tatsächlichen Services abgerufen. context.registerService(ContactRepository.class.getName(), rameter übergeben wird. Aufgrund der Die hierfür wichtigsten Methoden des new InMemoryContactRepository(contacts), properties); BundleContext lauten: Dynamik von OSGi muss unbedingt nochmals auf null geprü werden (Lis- ServiceReference getServiceReference(String clazz); ting 2), denn es könnte ja vorkommen, ServiceReference[] getServiceReferences dass im Moment zwischen der Abfrage Listing 2 (String clazz, String filter); der ServiceReference und des Service Object getService(ServiceReference reference); ServiceReference[] references = dieser deregistriert wurde. context.getServiceReferences(ContactRepository.class. In unserem Beispiel geben wir zum getName(), null); einen den Wert der Service Property Der Grund für die gerade aufgeführte if (references != null) { // Check if any service registered contactRepository.name aus, also den Mehrdeutigkeit ist einfach zu erklären: for (ServiceReference reference : references) { Namen des ContactRepository. An- Es können unter demselben Service In- ContactRepository contactRepository = (ContactRepository) schließend geben wir die Namen aller terface beliebig viele Services registriert context.getService(reference); enthaltenen Contacts aus. Um das Bei- werden, wohlgemerkt auch gar keiner. if (contactRepository != null) { // Check again! System.out.println(MessageFormat.format( spiel auszuführen, legen wir eine OS- Der Nutzer kann daher a priori nicht “All contacts of {0}:“, Gi Framework Run Con guration an, wissen, wie viele Services registriert reference.getProperty(ContactRepository.NAME))); nehmen unsere Bundles sowie deren sind, und muss mit dieser inhärenten Contact[] contacts = contactRepository.getAllContacts(); Abhängigkeiten auf und starten zuerst Mehrdeutigkeit umgehen. Die Metho- for (Contact contact : contacts) { com.weiglewilczek.example.osgi.con- de getServiceReferences() ermöglicht System.out.println(MessageFormat.format(“{0} {1}“, tacts.inmemory und danach com.wei- durch die Verwendung eines Filters, die contact.getFirstName(), contact.getLastName())); glewilczek.example.osgi.contacts.shell. Ergebnismenge einzuschränken. Sie ... Diese Startreihenfolge ist wichtig, da so- liefert für alle passenden Services eine ServiceReference zurück. Anders die wohl das Registrieren als auch das Kon- Methode getServiceReference(). Hier sumieren der Services im Beispiel beim Listing 3 Starten erfolgt. Wenn die Reihenfolge wendet bereits das OSGi Framework ei- private final class ContactRepositoryTracker extends ServiceTracker { umgedreht wird, werden wir keinerlei ne Heuristik an, die die Ergebnismenge @Override Ausgabe sehen. Dieses Verhalten ist auf einen Service einschränkt, sofern public Object addingService(ServiceReference reference) { höchst problematisch, denn bei einem überhaupt passende registriert sind. ContactRepository contactRepository = (ContactRepository) dynamischen modularen System kann Dabei wird der Service zurückgeliefert, super.addingService(reference); if (contactRepository != null) { // Check again! System.out.println(MessageFormat.format(“All contacts of {0}:“, Service Property Bedeutung reference.getProperty(ContactRepository.NAME))); Contact[] contacts = contactRepository.getAllContacts(); objectClass: String[] Service Interfaces der Registrierung, vom OSGi Frame- for (Contact contact : contacts) { work gesetzt System.out.println(MessageFormat.format(“{0} {1}“, service.id: Long Eindeutige Service ID, vom OSGi Framework gesetzt contact.getFirstName(), contact.getLastName())); service.ranking: Integer Wenn mehrere Services zu einer Anfrage über getService- ... Reference() passen, dann wird derjenige mit dem höchs- ten Wert zurückgeliefert, der Default entspricht 0 Tabelle 1: Wichtige Standard-Service-Properties 16 javamagazin 2|2009 www.JAXenter.de
  4. 4. OSGi in kleinen Dosen – Teil 3 Java Core die Startreihenfolge kaum kontrolliert werden. Service Properties und Filter Wir haben bereits eine Möglichkeit kennengelernt, wie man Service Pro- perties nutzen kann, und zwar als In- formationsträger. Eine weitere Mög- Abb. 3: Anwendung von Filtern in der Equinox Console lichkeit von besonderer Bedeutung ist die Verwendung in Filtern, um die reference) Ergebnismenge beim Abrufen von Ser- oder eine über Filter eingeschränkte Un- public Object waitForService(long timeout) viceReferences einzuschränken. Wie termenge erhalten. bereits beschrieben, verwendet das void addServiceListener(ServiceListener listener); Im Beispiel wird der ServiceTracker da- OSGi Framework die Service Property void addServiceListener(ServiceListener listener, service.ranking dazu, beim Aufruf von zu verwendet, obiges Problem mit der String filter); getServiceReference() einen eindeu- Startreihenfolge zu lösen (Listing 3). tigen Treffer zu ermitteln. Natürlich Indem nicht mehr zu einem festen Zeit- können wir auch beliebige eigene Ser- Aufgrund von Nebenläufigkeit kann punkt aktiv ContactRepository Services der Umgang mit diesen ServiceListeners vice Properties de nieren und diese in abgerufen wird, sondern auf deren Re- Filtern nutzen. recht diffizil sein. Soll beispielsweise gistrierung „gelauscht“, spielt es keine Wie sieht nun ein Filter aus? OSGi eine jederzeit aktuelle Liste von Servi- Rolle mehr, welches Bundle zuerst ge- verwendet dazu ein besonderes For- ces eines bestimmten Typs vorgehalten startet wird. mat: Die „String Representation of werden, so besteht die Gefahr, Duplikate Schlussbemerkung und LDAP Search Filters“ [3]. Die Syntax zu erzeugen oder einzelne Services aus- Ausblick beruht auf der polnischen Notation, zulassen. Daher spezifiziert das OSGi Service Compendium mit dem Service bei der zuerst die Operatoren und da- Das OSGi Service Model komplettiert Tracker eine Hilfsklasse, die mögliche Ra- nach die Operanden geschrieben wer- die bereits im letzten Teil vorgestell- den. Abbildung 2 visualisiert die Filter- ce Conditons und andere Schwierigkei- ten Eigenschaften der Modularisie- syntax in einem Syntaxdiagramm. Im ten berücksichtigt und damit die Beherr- rung und Laufzeitdynamik. Das OSGi Folgenden zwei Beispiele: schung der Servicedynamik vereinfacht. Framework vereinigt diese Kernprin- Wir empfehlen, in der Regel nicht direkt zipien zu einem dynamischen und (objectClass=com.weiglewilczek*) mit ServiceListeners zu arbeiten, sondern serviceorientieren Modulsystem, das (&(objectClass=com.weiglewilczek*)(service. den ServiceTracker zu verwenden. Dieser großen und vielfältigen Nutzen für die ranking>=10)) bietet nicht nur die gerade beschriebene Java-Entwicklung bringt, z. B. durch Möglichkeit der Serviceliste, sondern u. a. Reduktion von Komplexität, Gewinn auch Methoden, um auf Registrieren und an Flexibilität oder Chancen für Wie- Unser Beispiel ist zu einfach, um Fil- Deregistrieren zu reagieren oder eine be- derverwendung. Im nächsten Teil ter im Code zu verwenden. Aber die stimmte Zeit auf einen Service zu warten. wenden wir uns einem fortgeschritte- Equinox Console ermöglicht bei der nen ema zu: Der Möglichkeit, OSGi Verwendung des Kommandos die An- deklarativ und komponentenorientiert gabe eines Filterausdrucks. Wenn wir public Object[] getServices() einzusetzen. das Beispiel starten und den ersten public Object addingService(ServiceReference oben aufgeführten Beispiel lter einge- ben, werden genau die beiden Services Heiko Seeberger ist als Technical Director für die Weigle Wilczek GmbH ausgegeben (Abb. 3). tätig. Sein technischer Schwerpunkt liegt in der Entwicklung von Unterneh- mensanwendungen mit OSGi, Eclipse RCP, Spring, AspectJ und Java EE. Services und Dynamik Seine Erfahrungen aus über zehn Jahren IT-Beratung und Softwareent- wicklung fließen in die Eclipse Training Alliance ein. Zudem ist Heiko OSGi ist ein dynamisches System und Seeberger aktiver Committer in Eclipse-Projekten, Autor zahlreicher Fachartikel und dies gilt insbesondere für Services. Kon- Redner auf einschlägigen Konferenzen. sumenten müssen mit dieser inhärenten Dynamik umgehen. Dafür bietet das Links & Literatur OSGi Framework die Möglichkeit, auf ServiceEvents zu reagieren, also insbe- [1] Eclipse SDK: www.eclipse.org/downloads sondere auf das Registrieren und De- [2] WeigleWilczek-Examples: www.weiglewilczek.com/examples/ registrieren. Über den BundleContext [3] String Representation of LDAP Search Filters: www.ietf.org/rfc/rfc1960.txt können ServiceListeners angemeldet werden, die entweder alle ServiceEvents javamagazin 2|2009 17 www.JAXenter.de

×