Entwurf und Implementierung einer dynamischen Funktionalitätsanpassung von myHealthAssistant Bachelorarbeit Dassi Ponka | 1254729 Informatik Abbildungsverzeichnis 1 myHealthHub-Interaktionsmodell . . . . . . . . . . . . . . . . . . . . . . . . . 3 2 Android Software-Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 3 Buildprozess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 4 OSGi-Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 5 manifest-file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 6 Lebenszyklus eines Bundles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 7 System-Übersicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 8 Felix in Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 9 Client-Server-Interaktion in REST . . . . . . . . . . . . . . . . . . . . . . . . . 23 10 Umwandlungsfluss ein Bundles . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 11 Klassen für die Integration von OSGi in Android . . . . . . . . . . . . . . . . 29 12 Struktur des ECGtoHR-Transformationsprojekts . . . . . . . . . . . . . . . . 33 13 Struktur des Remote-Repository-Projekts . . . . . . . . . . . . . . . . . . . . 35 14 Installation einer Transformation . . . . . . . . . . . . . . . . . . . . . . . . . . 40 1 Dassi Ponka Matrikelnummer: 1254729 Studiengang: Informatik Bachelorarbeit Thema: Entwurf und Implementierung einer dynamischen Funktionalitätsanpassung von myHealthAssistant Eingereicht: 15. Mai 2013 Betreuer: Christian Seeger Prof. Alejandro Buchmann Fachgebiet Databases and Distributed Systems / Informatik Technische Universität Darmstadt Hochschulstraße 10 64289 Darmstadt Ehrenwörtliche Erklärung Ich erkläre hiermit ehrenwörtlich, dass ich die vorliegende Arbeit selbstständig angefertigt habe; die aus fremden Quellen direkt oder indirekt übernommenen Gedanken sind als solche kenntlich gemacht. Die Arbeit wurde bisher keiner anderen Prüfungsbehörde vorgelegt und auch noch nicht veröffentlicht. Darmstadt, den Unterschrift 3 Inhaltsverzeichnis Abbildungsverzeichnis 1 1 Einleitung 1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Aufgabenstellung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Zielsetzung und Aufbau der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . 1 1 2 3 2 Verwandte Arbeit 2.1 Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Die Netscape-Plugin-Programmierschnittstelle . . . . . . . . . . . . . . . . . 4 5 5 3 Grundlagen 3.1 Android . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Android-Laufzeitumgebung . . . . . . 3.1.1.1 Dalvik Virtual Maschine . . 3.1.1.2 Buildprozess . . . . . . . . . 3.1.2 Ressourcen . . . . . . . . . . . . . . . . 3.1.3 Android Komponenten . . . . . . . . 3.1.3.1 Activities . . . . . . . . . . . 3.1.3.2 Services . . . . . . . . . . . . 3.1.3.3 Broadcast-Receiver . . . . . 3.1.3.4 Android-Context . . . . . . 3.1.4 Komponentenkommunikation . . . . 3.1.4.1 Intent . . . . . . . . . . . . . 3.2 OSGi-Grundlagen . . . . . . . . . . . . . . . . 3.2.1 OSGi-Architektur . . . . . . . . . . . 3.2.2 OSGi-Bundle . . . . . . . . . . . . . . 3.2.2.1 Manifest-Datei . . . . . . . . 3.2.2.2 Lebenszyklus eines Bundles 3.2.3 Deklarative Services . . . . . . . . . . 3.3 REST Web Service . . . . . . . . . . . . . . . 3.3.1 Grundprinzipien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 8 9 9 10 10 10 11 11 11 11 12 12 13 14 15 16 17 18 18 I 4 Konzeption 4.1 Konzeption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Integration des OSGi-Frameworks in Android . . . . . . . . 4.1.1.1 Interaktion zwischen OSGi-Bundles und Android 4.1.2 Remote-Repository . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.3 Kommunikation mit dem Remote-Repository . . . . . . . . . 5 Implementierung 5.1 Verwendete Tools . . . . . . . . . . . . . . . . . . . . . . 5.1.1 Software Development Kit . . . . . . . . . . . . 5.1.1.1 Android Debug Bridge (adb) . . . . . 5.1.1.2 dx-Tool . . . . . . . . . . . . . . . . . . 5.1.2 Apache Maven . . . . . . . . . . . . . . . . . . . 5.1.2.1 pom.xml . . . . . . . . . . . . . . . . . 5.2 Integration von Apache Felix in Android . . . . . . . . 5.3 Erstellung einer Transformation . . . . . . . . . . . . . 5.3.1 Verwaltung von Transformators . . . . . . . . . 5.4 Umsetzung des Remote-Repositorys . . . . . . . . . . . 5.4.1 Struktur des Projekts . . . . . . . . . . . . . . . 5.4.2 Konfiguration des Webservers . . . . . . . . . . 5.4.3 Remote-Repository REST-konform Entwickelt 5.4.3.1 REST mit Jersey . . . . . . . . . . . . 5.4.4 Speicherung von Transformationen . . . . . . . 5.5 Kommunikation mit dem Remote-Repository . . . . . 5.6 Installation einer Transformation . . . . . . . . . . . . . 5.6.1 Ablauf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 20 21 22 22 23 . . . . . . . . . . . . . 25 25 25 25 25 26 27 29 32 34 34 35 35 36 36 38 38 39 39 6 Fazit und Aussicht 6.1 Fazit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Aussicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 41 41 Abkürzungsverzeichnis 42 Literaturverzeichnis III Inhaltsverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . II 1 Einleitung 1.1 Motivation Die Technische Universität Darmstadt vor allem das Fachgebiet Database and Distributed Systems (DVS) befasst sich mit Sensornetzwerken und Anwendungen für Assistenzsystem zur Unterstützung im täglichen Leben. Eine dieser Anwendung ist myHealthHub, eine Middleware für Sensornetze, die auf dem Betriebssystem Android basiert. Um die Qualität und vor allem die Akzeptanz von myHealthHub zu erhöhen, ist es von Vorteil, seine Funktionalitäten und Benutzbarkeit besser und flexibel zu gestalten. Aus diesen Gründen wird in der Middelware ein Plugin1 -System eingeführt, so dass das System sich in Zukunft (im Gegenteil eines monolithischen Systems) dynamisch anpassen kann. Ein monolithisches System lässt sich meistens nicht an die individuellen Bedürfnisse und Wünschen des Benutzers in der Hinsicht anpassen, dass bestimme Funktionalitäten und Module des Gesamtsystems nicht ausgewechselt oder ersetzt werden können. Zudem kann ihre Verfügbarkeit nur schwer gewährleistet werden. In solchen Systemen können Systemteile nur schwer herausgelöst oder ersetzt werden. Mit wachsender Größe werden die so realisierten Anwendungen immer komplexer und nur schwer beherrschbar. Für bestimmte Anwendungen ist eine sehr hohe Verfügbarkeit in dem Sinne erforderlich, dass sie nicht gestoppt werden können. Wichtig ist dies speziell für lebenskritische Anwendungen - so genannte safety-of-Life applications wie myHealthHub. Deshalb Operationen wie die Bereitstellung neuer Versionen, Patches oder Erweiterungen während der Laufzeit stattfinden müssen. Eine Unterbrechung dieser Systeme würde hohe Kosten und Verlust der Benutzerfreundlichkeit nach sich ziehen und kann sogar lebensbedrohlich sein. Flexible Anwendungen, die in der Lage sind, ihr Verhalten zur Laufzeit an ein sich immer veränderndes Umfeld anzupassen, gewinnen mehr und mehr an Bedeutung. Der Bedarf an solchen Anwendungen ist vor allem dadurch begründet, dass mobile Anwendungen zunehmend benutzt werden und die Nutzer vor allem an Anwendungen interessiert sind, die sich dem aktuellen Kontext anpassen können. In diesem Fall ist die Integration eines Pluginsystems in die Software eine Lösung der sich ergebenden Probleme. Damit ist es 1 Ein Plugin ist eine Software Komponente, die sich über eine definierte Schnittstelle in ein Programm einklinken kann, um dessen Funktionalität zu erweitern. 1 möglich das System während seiner Entwicklung auf bestimmte Grundfunktionalitäten zu reduzieren und nach individuellen Bedürfnissen des Benutzers anpassen zu lassen, indem vorgefertigte Funktionalitäten nach Bedarf und auf einfachste Weise zum Softwaresystem hinzugefügt oder daraus entfernt werden 1.2 Aufgabenstellung Dynamische Anapassung - die Fähigkeit Komponenten zur Laufzeit zu ändern oder neue in ein System einzubringen - ist ein äußerst komplexe Angelegenheit und zugleich ein wesentliches Mittel, um evolutionäre Veränderung in einem langlebenden System zu bewerkstelligen. Die Probleme liegen bei dem Zusammenspiel vieler unabhängigen Faktoren wie Kosten, Zeit, Anwendungszustand und System-Ressourcen. Die Begrenzte Ressourcen in Embedded Systems, insbesondere Speichergröße und Rechnerleistung impliziert auch den Bedarf nach einem leichtgewichtigen Erweiterungsmechanismus, das das System nicht belasten soll. Die am Fachgebiet Database and Distributed System (DVS) entwickelte Kommunikationsmiddleware für Sensornetze wird eingesetzt, um die von Sensoren gesendeten Daten zu bearbeiten. Die Kommunikation von Sensoren zur Middleware erfolgt durch eine Bluetooth-Verbindung. Die Mehrheit der Sensoren, die im Moment eingesetzt werden, sind nicht rekonfigurierbar. Die aktuellen Sensoren sind so entwickelt, dass sie nur Daten mit bestimmten Inhalt und in einer bestimmten Form senden können. Deswegen besteht keine Möglichkeit den Sensoren mitzuteilen, was sie senden sollen. Die Abbildung 1a zeit die aktuelle funktionsweise der Middleware. In diesem Kommunikations- und Interaktionsmodell kann ein Benutzer die gewünschte Information nur dann bekommen, wenn myHealthHub im Zeitpunkt der Abfrage die entsprechenden Daten von einer angeschlossenen Sensor bekommt. Um den Einsatzbereich und die Akzeptanz der Middleware zu erhöhen, sollte die Abhängigkeit von Sensoren verringern werden, damit das System in der Lage sein wird, nur mit den nötigen Sensoren auszukommen. Das Abbild 1b zeigt das gewünschte Verhalten des Systems. Eine Softwarelösung in Form von dynamischen Modulen sollte den Einsatz von Sensoren kompensieren. Damit ist es nicht nur möglich die Kosten und Zeit zur Herstellung von Sensoren zu sparen, möglich ist es auch damit das System funktionsfähig im Betrieb zu halten, falls ein im Einsatz stehender Sensor plötzlich ausfallen würde. 1.2 Aufgabenstellung 2 (a) Aktueller Zustant (b) Zu erreichen Abbildung 1: myHealthHub-Interaktionsmodell 1.3 Zielsetzung und Aufbau der Arbeit Das grundlegende Ziel einer dynamischen Anpassung von Softwaresystemen besteht darin, einem System zu helfen, sich selbständig (ohne zusätzliche Benutzereingriffe) und dynamisch zu erweitern. Neue Funktionalitäten werden nicht sofort auf dem Softwaresystem installieren, sondern in einem Remote-Repository bereitgestellt. Die Funktionalitäten werden dann erst nach einer Abfrage dem System zur Verfügung gestellt. Eine Erweiterung sollte also einen Bestandteil des Systems werden, erst wenn sie vorher heruntergeladen und installiert wurde. In dieser Arbeit wird eine Softwarelösung entwickelt, die dem System helfen sollte, seine Abhängigkeit von Sensoren auf die notwendige Anzahl zu verringern und so seinen Einsatzgebiet und Akzeptanz zu steigen. Dafür wird eine mögliche Kombination von OSGi und REST (auch RESTful Webservices) als Grundlage für die Entwicklung eines dynamischen Anpassungsmechanismus für myHealthHub vorgestellt. In Kapitel 2 werden relevanten verwandten Arbeiten vorgestellt. Darauf folgt ein kurzer Überblick über die Android-Programmierung und die für die Realisierung dieser Arbeit relevante OSGi-Aspekte. Anschließend wird auf die Grundkonzepte von REST(auch RESTful Webservices) eingegangen. Die konzeptionelle Vorstellung dieser Arbeit erfolgt in Kapitel 4 gefolgt von der technischen Umsetzung in Kapitel 5. Abschließend werden in der Zusammenfassung (Kapitel 6) alle relevanten Ergebnisse der Arbeit zusammengefasst. 1.3 Zielsetzung und Aufbau der Arbeit 3 2 Verwandte Arbeit Das Problem der dynamischen Anpassung von Softwaresystemen ist nicht neu. Es ist fast so alt wie das Software-Engineering selbst. Es wurde aber vor allem mit der Entwicklung und Expansion von verteilten Systemen deutlich. Kramer und Magee gründete den Bereich der dynamischen Rekonfiguration2 mit ihrer Arbeit aus dem Jahr 1990. In [15] beschreiben sie wie ein System zur Laufzeit sicher geändert werden kann. Der Grundstein für ihren Ansatz war das so genannte „quiescence“-Konzept (das Ruhe-Konzept). Sie beschreiben ein System, in dem ein Programmierer die gewünschten Änderungen auf deklarative Weise angeben kann. Später wurden mehrere Forschungsarbeiten auf dem Gebiet betrieben. Es ist - insbesondere in den letzten Jahren - ein aktives Forschungsgebiet geworden. Aber nur sehr wenige Arbeiten konzentrieren sich auf eingebettete Systeme. Ein einfaches Verfahren zur Implementierung eines Pluginsystems in einer Objektorientierten Umgebung ist die Verwendung des Strategy Design Pattern[10]. Diese Lösung ermöglicht es, ein Algorithmus oder eine Strategie zur Laufzeit zu ändern. Das erfordert aber, dass die Anwendung vom Anfang an für zukünftige Anpassungen entworfen wurde und dass alle möglichen Strategien zur Kompilierungszeit des Systems bekannt sind. Daher ist so ein Verfahren für unvorhergesehene Aktualisierungen und vor allem für Systeme mit begrenzten Ressourcen nicht geeignet. Ein sehr flexible Lösung kann auf der Metaebene gefunden werden. Durch Reifikation objektorientierter Konzepten (Klassen, Methodenaufrufe, usw.) kann ein Metamodell über die Anwendung erstellt werden. Auf diese Weise ist es möglich, Änderungen an der Anwendung zu machen, indem das Metamodell geändert wird. Ein großer Vorteil dieses Ansatzes ist, dass eine saubere Trennung zwischen der Anwendung und den Code für die Rekonfiguration möglicht ist. Der Rest dieses Abschnitts beschreibt zwei wesentliche Ansätze, die die dynamische Anpassung von Softwaren unterstützen: Eclipse und die Netscape-PluginProgrammierschnittstelle. 2 ein technischer Vorgang, bei dem ein Softwaresystem dynamisch angepasst wird 4 2.1 Eclipse Eclipse ist als eine leistungsstarke integrierte Entwicklungsumgebung3 ( Integrated Development Enviroment (IDE)) unter Java-Entwicklern bekannt, ist jedoch nicht auf die Programmiersprache Java beschränk. Beim Übergang von Eclipse Version 2.1 zur Version 3.0 haben sich die Entwickler entschieden, ihre eigene Implementierung eines Plugin-Systems durch eine auf dem Framework der OSGi (Open Service Gateway Initiative) aufbauende Implementierung namens Equinox zu ersetzen. Der bisherige proprietäre Implementation wurde durch Equinox ersetzt und abgesehen von einem kleinen Kernsystem zur Integration von Plugins wird jegliche weitere Funktionalität, insbesondere die Java-Entwicklungswerkzeuge vollständig in Plugins ausgegliedert. Dadurch wird sie leicht erweiterbar und unterstützt das Erstellen und Nutzen von neuen Softwarewerkzeugen. Bei Eclipse-Plugins handelt es sich um statische Komponenten, die lediglich beim Start des Systems gesucht und registriert werden. Plugins werden in Eclipse als Java Klassen realisiert, welche von einer entsprechenden den Basis Klasse abgeleitet werden. Zusätzlich hat jedes Plugin ein XML basiertes Manifest, welches das Plugin und seine Verbindungen zu anderen Plugins beschreibt. Plugins können sich gegenseitig um Funktionalität erweitern. Diese Verbindungen stellen ein Mechanismus dar, mittels dessen Bundles untereinander kommunizieren können. Sie werden als „Extension Points“ genannt. Ein Plugin kann mehrere solche Verbindungen bereitstellen. Ein oder mehrere Plugins können diese Schnittstelle nutzen und nehmen dabei die Rolle des Extenders ein. Das Pluginsystem, das von Eclipse geboten wird ist flexibel und mächtig, da Plugins über Extension Points verschachtelt werden können. Es hat aber den Nachteil, lediglich statische Komponenten zu unterstützen. Derzeit entsteht ein Modell für dynamische Plugins. Das Projekt befindet sich im Moment noch in der Entwicklung. 2.2 Die Netscape-Plugin-Programmierschnittstelle Netscape Plugin Application Programming Interface (NPAPI) ist eine Cross-PlattformPlugin-Architektur, die von vielen Web-Browsern verwendet wird. Mit dem NPAPI kann der Umgang mit unbekannten Ressource-Typen zu externen Plugins delegiert werden. 3 Als Entwicklungsumgebung wird eine Anwendung bezeichnet, mit der es möglich ist, Software in einer oder mehreren Programmiersprachen zu entwickeln 2.1 Eclipse 5 Netscape-Plugins werden als plattformspezifische dynamische Bibliotheken ausgeliefert. Einmal installiert, können diese Plugins nahtlos in Webseiten integrieren werden. Beliebte Browsern wie Chrome, Firefox, Opera Safari sowie älteren Versionen von Internet Explorer unterstützt diese Art von Plugins. Um durch den Browser geladen werden, muss ein NPAPI-Plugin eine bestimmte Gruppe von Funktionen erklären. Diese Funktionen werden vom Browser aufgerufen, um die Plugin-Funktionen aufzuzählen oder das Plugin über neuen Bedingungen, wie der Abschluss einer URL-Anforderung oder Änderungen des Fensters, zu informieren. Damit kann der Plugin-Lebenszyklus vom Webbrowser kontrolliert werden. Das Plugin wird bei Bedarf vom Browser aktiviert, je zu präsentierendem Datenobjekt eine Instanz des Plugins erzeugt und auch wieder vernichtet, sobald kein Bedarf mehr besteht. Auf der anderen Seite stellt der Browser eine Reihe von Funktionen dem Plugin zur Verfügung. Damit entsteht eine Bidirektionale Interaktion zwischen Plugins und dem Browser. Für die korrekte Installation eines Plugins auf dem System des Anwenders ist in der Regel der Plugin-Hersteller zuständig, so dass diese außerhalb der Kontrolle des Webbrowsers erfolgt[9]. 2.2 Die Netscape-Plugin-Programmierschnittstelle 6 3 Grundlagen In diesem Kapitel soll ein Überblick über die technischen Grundlagen gegeben werden, auf denen diese Arbeit aufbaut. Auch wenn all die Möglichkeiten der in dieser Arbeit verwendeteten Technologien nicht eingehend behandelt werden können, soll auch ein möglichst umfassender Überblick über sie geliefert werden. Auf diese Weise können die Konzepte hinter der einzelnen Technologie am besten verstanden und auch die Möglichkeiten, die sich daraus ergeben erkannt werden. Das Augenmerk liegt dabei hauptsächlich auf die Möglichkeit, sie am besten zusammenarbeiten zu lassen. Zunächst soll Android betrachtet werden, da es in dieser Arbeit indirekt darum geht, ein Pluginsystem in Android zu integrieren. Danach soll auf OSGi eingegangen werden. Da ein Plugin (in dieser Arbeit als Transformation genannt) erst nach Bedarf heruntergeladen werden soll und ein RESTful Web Service dafür eingesetzt wird, soll auch kurz die Architektur von REST-basierten Webservices beschrieben werden. 3.1 Android Android ist zugleich ein Betriebssystem und eine Software-Plattform für mobile Endgeräte wie Smartphones, Mobiltelefone und Netbooks. Es wurde von Google und der Open Handset Alliance[7] entwickelt, wobei ein großer Teil der Software frei und quelloffen ist. Die Open Handset Alliance (OHA) ist eine in 2007 von Google initiiertes Bündnis von über 60 namhaften internationalen Mobilfunkanbietern, Softwarefirmen, Mobiltelefon-Hersteller, Halbleiterfirmen und Netzbetreiber, das die Vision einer offenen, mobilen Plattform realisieren soll[4]. Durch die Möglichkeit für Gerätehersteller Android kostenlos zu nutzen, wird es gerne eingesetzt. Um ein besseres Verständnis über die Funktionsweise von Android zu erlangen, ist es wichtig mehr über seine Laufzeitumgebung zu erfahren. Es soll auch die Komponententypen und deren Interaktionen untersucht werden. Nicht zu vernachlässigen ist der Buildprozess einer Android-Anwendung. Da der Umgang mit Ressourcen eine bedeutende Rolle in allen Anwendungen spielt, soll auch betrachtet werden, wie Android sie verwalten. 7 3.1.1 Android-Laufzeitumgebung Android basiert auf einem Linux Kernel. Für mobile Bedürfnisse wurde der Linux Kernel um weitere Module4 wie Kernel-Debugger, Binder, Logger, eine verbesserte Energieverwaltung und einen Low Memory Killer erweitert. Treiber, die für ein solches System unwichtig sind, wurden entfernt. Andere Treiber etwa für spezielle Tastaturen oder eingebaute Kameras, hinzugefügt. Android ist ein kompletter Software-Stack5 , der ein Linux-Kernel, eine Middleware und ein paar nützliche Anwendungen umfasst. Die Abbildung 2 zeigt seinen Software-Stack. Die oberste Schicht umfasst Portable User-Anwendungen, die in Java programmiert wur- Abbildung 2: Android Software-Stack den. Diese stützen sich auf die nächste Schicht, die eine Vielzahl von Java-APIs exportiert und eine Reihe von Dienstleistungen bietet, um die Entwicklung von Anwendungen zu er4 5 Ein Modul ist eine abgeschlossene funktionale Einheit einer Software, deren Funktionalitäten über eine definierte Schnittstelle zugegriffen werden Ein Software-Stack ist eine besondere Softwaredefinition, mit der Sie Softwaregruppen identifizieren können, die Sie gleichzeitig und in einer bestimmten Reihenfolge auf Zielsystemen installieren möchten. 3.1 Android 8 leichtern. Es sind z.B die Content-Manager, Ressourcen-Manager, View-Dienste usw. Die nächste Schicht besteht aus C/C++ System-Bibliotheken und die Android Runtime. Die System-Bibliotheken beinhaltet: • System C library (libc) • Media library • SQLite (database engine) • SGL (to support 2-D graphics) Kern der Laufzeitumgebung bildet die Dalvik Virtual Maschine6 (Dalvik VM) zusammen mit ihren Kernbibliotheken. 3.1.1.1 Dalvik Virtual Maschine Jede Android-Anwendung läuft in einem eigenen Linux-Prozess. Jeder Prozess auf Android hat eine eigene Instanz der Dalvik VM, die zusammen mit dem Prozess erstellt und zerstört, wenn der Prozesse terminiert. Dalvik Virtual Maschine fungiert als Interpreter7 für Java-Code. Im Gegensatz zur Java VM (JVM), die auf einen Kellerautomaten basiert, arbeitet die Dalvik VM als Registermaschine[16]. Dadurch können Berechnungen stark beschleunigt werden. Eine auf Register basierte virtuelle Maschine holt ihre Bytecodes und Operanden aus Registern. Dies hat zur Folge, dass herkömmlicher Java-Bytecode ins Dex-Format (Dalvik Executable) überführt werden müssen, damit sie auf der Dalvik VM zur Ausführung gebracht werden können[17]. Der Speicherverbrauch wurde etwa dadurch verringert, dass Redundanzen im Bytecode entfernt wurden. Vor allem ist das Modell der Registermaschine in Bezug auf den begrenzten Ressourcen (Speicherplatz, Rechenleistung) für mobile Geräte wesentlich besser geeignet. 3.1.1.2 Buildprozess Im ersten Schritt des Buildprozesses einer Android-Anwendung werden die JavaCode von einem Java-Compiler in Java-Bytecode kompiliert. Für jede Java-Klasse entsteht eine Class-Datei. Diese werden, zusammen mit Ressourcendateien wie die AndroidManifest.xml-Datei, XML-Dateien und möglichen Drittanbieter-Bibliotheken, 6 7 Eine virtuelle Maschine (VM) ist eine hohe Abstraktion auf das native Betriebssystem, dass eine physikalische Maschine emuliert. Der Interpreter ist eine Software-Bibliothek, die Eingaben und Quelltext entgegen nimmt und zur Laufzeit interpretiert. 3.1 Android 9 von dx (ein Programm im Android Development Kit) in Dalvik-Bytecode überführt. Die entstandenen Dalvik-Bytecode werden in einer einzigen Dex-Datei gebündelt. Zuletzt wird die Dex-Datei und alle weiteren Dateien, die von der Anwendung genutzt werden sollen, in einer .apk-Datei zusammengefasst. Die Datei kann später von einem Android-Geräte entpackt werden. Abbildung 3 veranschaulicht den Buildprozess einer Android-Anwendung. Abbildung 3: Buildprozess 3.1.2 Ressourcen Jedes Android-Projekt hat einen /res/-Ordner mit weiteren Unterverzeichnissen. Wichtig für diese Arbeit war das Unterverzeichnis /res/raw. Dort können binäre Daten abgelegt werden. Diese Daten sind durch die Ressourcen-Klasse (R-Klasse) erreichbar. Hierzu wird für jede Ressource eine eindeutige Kennung erstellt. Dadurch kann eine Ressource leicht zur Laufzeit angesprochen werden. 3.1.3 Android Komponenten Android definiert ein einfaches Komponentenmodell. Jede Komponente verfügt über einen Lebenszyklus, welcher definiert, wie die Komponente erzeugt und zerstört wird. Im folgenden sollen die Android-Komponenten und Klassen vorgestellt werden, die für diese Arbeit wichtig wurden. 3.1.3.1 Activities Eine Activity stellt die Benutzeroberfläche einer Anwendung dar. Sie kümmern sich um die Darstellung von Daten und nehmen Anwendereingaben entgegen. Wenn zwischen den Screens gewechselt werden soll, wird eine neue Activity aufgerufen und die vorherige pausiert. Sie sind deshalb nicht geeignet, persistenten Daten zu halten. 3.1 Android 10 3.1.3.2 Services Services erledigen Hintergrundprozesse und können sowohl im Prozess der aufrufenden Komponente als auch in einem eigenen Prozess gestartet werden. Bei dem Service, welcher im gleichen Prozess wie die Anwendung läuft, spricht man von einem Local Service. Der im eigenen Prozess laufenden Service nennt man Remote Service. Mithilfe eines Services können Programmlogiken ausgelagert werden. Sie sind gut geeignet für die Bereitstellung von langfristigen Diensten. Eine Service-Komponente kann als wichtig deklariert wird. Dadurch wird sie erst gestoppt, wenn dem System den Speicherplatz ausgeht. 3.1.3.3 Broadcast-Receiver Broadcast-Receiver wurden gemäß den Publisher/Subscriber implementiert. Apps(die als Publisher, Herausgeber, bezeichnet werden) können einen Broadcast senden, um einfach Informationen zu übermitteln, ohne zu wissen wer und ob überhaupt jemand sie empfängt. Die Receiver(die als Subscriber, Empfänger bezeichnet werden), die diese Nachrichten haben wolllen, registrieren sich über Filter für bestimmte Events. Wenn die Nachricht einem Filter entspricht, wird der Subscriber aktiviert und über die Meldung benachrichtigt[13]. 3.1.3.4 Android-Context Die Klasse android.content.Context bildet die Schnittstelle für eine Android-Anwendung zur Laufzeitumgebung. Über die Methoden der Klasse lassen sich alle Komponenten und Dienste der Plattform (Android) ansprechen. Damit die vorgestellten Komponenten miteinander interagieren können, bietet Android interessante Mittel zur Kommunikation. 3.1.4 Komponentenkommunikation Die Anwendungen und System-Dienste in Android verhalten sich wie in einem verteilten System. Jede Android Applikation läuft in eigener virtuellen Maschine. Möchte man auf Ressourcen, die außerhalb der Sandbox8 liegen, zugreifen, müssen dafür explizit Berechtigungen vergeben werden. Der offizielle Weg unter Android eine Kommunikation zwischen Anwendungen herzustellen, sind Intents, RPC-Aufrufe mittels Binder und AIDL. 8 http://de.wikipedia.org/wiki/Sandbox 3.1 Android 11 3.1.4.1 Intent Intents sind eine Möglichkeit der Kommunikation zwischen Komponenten oder Prozessen in Android. Android nutzt Intents für Inter- und Intra-Anwendung-Kommunikation. Ein Intent stellt eine Nachricht in Form einer Datenstruktur dar. Die Struktur enthält optional einen Empfänger und eine abstrakte Beschreibung einer Operation, die Action genannt wird. Die Intents lassen sich in zwei Kategorien unterteilen • explizite Intents: Hier wird der Empfänger direkt angegeben. Dies erfolgt über den vollständigen Name der Komponente. • implizite Intents: Hier wird kein direkter Empfänger dieser Nachricht genannt und können daher von jeder Anwendung empfangen werden. Die Erweiterungseinheiten (auch als Transformation genannt) in myHealthHub sind dynamische Software-Module, die als OSGi-Bundle implementiert werden. Der kommende Abschnitt dient als Einführung in die OSGi Service Plattform und definiert zugleich den Grund, warum OSGi eingesetzt werden soll. 3.2 OSGi-Grundlagen OSGi steht für Open Service Gateway Initiative und ist ein Konsortium, welches sich der Entwicklung und Standardisierung einer Java-Laufzeitumgebung für Dienste widmet. OSGi ist ein leichtgewichtiges Framework, dessen Schwerpunkt auf der Entwicklung von dynamischen Systemen liegt. Um die Portabilität auf unterschiedliche Hardware zu gewährleisten, setzt OSGi auf Java. Softwaresysteme, die auf OSGi aufbauen, können zur Laufzeit sowohl lokal als auch entfernt aktualisiert werden ohne, dass das darunterliegende System gestoppt wird. Die Gründe für den Einsatz von OSGi liegen darin, dass die Java Standard Edition nur eingeschränkte Möglichkeiten zur Modularisierung bietet. Als Mittel zur Modularisierung in Java dienen Klassen, Pakete und die JAR-Dateien. Klassen sind in den meisten Fälle zu kleine Einheiten, um als Modul verwenden zu können. Java-Pakete hingegen können keine Kapselung gewährleisten, da sie jederzeit erweitert werden. Ihre Aufgabe ist es, Namensräume zu definieren. Standardmäßig sind JAR-Dateien die Auslieferungsmethode von Software für die Java-Plattform. Sie bieten zwar schon die Möglichkeit, ausführbaren Code und gegebenenfalls weitere Ressourcen zu bündeln, haben aber folgenden Nachteile: • Sie bieten Keine Unterstützung für Versionierung 3.2 OSGi-Grundlagen 12 • Abhängigkeiten zu anderen JAR-Dateien sind implizit • Sie bieten Keine Unterstützung für JAR-Dateien als Einheit der Kapselung JAR-Dateien werden lediglich als Einheit der Auslieferung benutzt. Deswegen gibt es in Java keine Laufzeitentsprechung, durch die eine JAR-Datei repräsentiert wird. Was aber für die diese Arbeit von größer Bedeutung ist. Denn die Transformators sollen als Module bereitgestellt werden[18]. Die OSGi Service Platform ist ein sehr mächtiges Framework, dessen Architektur klar strukturiert ist. 3.2.1 OSGi-Architektur Die Architektur der OSGi-Plattform ist schichtweise organisiert. Jede Schicht ist verantwortlich für eine Reihe von spezifischen Aufgaben, die im Zusammenhang mit der Integration eines Bundels in die Plattform steht. Diese Schichten werden wie folgt erläutert: Abbildung 4: OSGi-Architektur • Betriebssystem/Hardware: Auf der untersten Ebene befinden sich die Hardware und ein entsprechendes Betriebssystem. Die Hardware und das Betriebssystem können von verschiedenen Herstellern kommen. Für das Betriebssystem muss eine Java Laufzeitumgebung existierten, die die OSGi Spezifikation mindestens in der Version 1.0 erfüllt. • Execution Environment: Eine Ebene höher liegt das Execution Environment. Dieser besteht aus einer Java Laufzeitumgebung. Dabei werden verschiedene Editionen, wie zum Beispiel Java SE9 , CDC10 , und MIDP11 unterstützt. 9 10 11 http://java.sun.com/javase/ http://java.sun.com/javame/technology/cdc/ http://java.sun.com/products/mipd/ 3.2 OSGi-Grundlagen 13 • Module Layer: definiert ein Modularisierungsmodell fur Java. Dieser Schicht erlaubt es, Modularisierungsprinzipien in Java auf größere Einheiten als Klassen anzuwenden. Diese Einheiten werden in OSGi als „Bundles“ bezeichnet und als Java Archive (JAR) repräsentiert. • Life Cycle Layer: Das Life Cycle Layer bietet die API für die Verwaltung des Lebenszyklus von Bundles. Dort wird definiert, wie Bundles installiert, aktualisiert, deinstalliert, gestartet und gestoppt werden können. • Service Layer: Die Serviceschicht erweitert die bisher vorgestellten Schichten um eine „Service Registry“, welche eine serviceorientierte Entwicklung innerhalb von OSGi ermöglicht. Es definiert ein Kommunikationsmodell fur die Kooperation von OSGi-Modulen • Security Layer: ist ein optional. Der Security Layer stellt auf Basis von Java 2 Security spezifische Sicherheitsbelange zur Verfügung. Es kann z.B. festgelegt werden, ob ein Bundle berechtigt wird, bestimmte Services zu verwenden oder das API anderer Bundles zu nutzen. Ein wichtiges Konzept in OSGi ist die Sichtbarkeit von Klassen. Jedem Bundle wird ein Classloader zugewiesen. Mit dem Classloader werden alle Klassen und Ressourcen des Bundles geladen. Dadurch können verschiedene Versionen eines Bundle in derselben Java Virtual Machine benutzt werden. Mit diesem Mechanismus ist es auch möglich, verschiedene Instanzen einer Klasse zu unterscheiden. OSGi spezifiziert ein dynamisches Modulsystem fur Java. In der OSGi Service Platform werden Bundles als Einheit für Modularisierung verwendet. 3.2.2 OSGi-Bundle Ein Bundle in der OSGi Service Plattform ist die Modularisierungseinheit. Grundsätzlich sind Bundels regulären JAR-Dateien mit class-Dateien und anderen Ressourcen wie Bilder, benötigten APIs und einer Manifest-Datei. Ein Bundle kann auch weitere JARDateien beinhalten, die so seinen Classpath erweitern. Die Funktionalität eines Bundles werden in Form eines oder mehrerer dynamischen OSGi Services12 verfügbar gemacht. Diese Services werden an einer zentralen Registratur (Service Registry genannt) unter einem oder mehreren Interface- oder Klassennamen angemeldet und können so von anderen Bundles gefunden und verwendet werden. In der OSGi-Architektur ist ein Service 12 Ein OSGi Service ist ein einfaches Plain Old Java Object (POJO). 3.2 OSGi-Grundlagen 14 ein Standard-Java-Objekt, das mit einem oder mehreren Interface-Typen und weiteren Eigenschaften (die verwendet werden können, um den Dienst zu finden) registriert ist. Die Entitäten, die sich in einem Bundle befinden, sind nicht implizit von außen sichtbar. Sie müssen explizit exportiert werden, damit sie von anderen Bundles benutzt werden können. Jedes Bundle muss eine Manifest-Datei beinhalten. 3.2.2.1 Manifest-Datei Abbildung 5: manifest-file Die Metadaten eines Bundles stehen in der Manifest-Datei und die Datei muss in einem Ordner names META-INF liegen. In der Manifest-Datei steht unter anderem welche Abhängigkeiten das Bundle besitzt bzw. welche anderen Java-Pakete es benötigt. Dort steht auch welche Pakete das Bundle selbst definiert und exportiert. Jedes Bundle besitzt einen obligatorischen symbolischen Namen, der mittels Bundle-SymbolicName (Ein Manifest-Header) spezifiziert wird. In der Menge der Manifest-Header sind folgende Angaben wichtig: • Bundle-SymbolicName: Eindeutiger Name innerhalb des OSGi Frameworks. Obligatorisch. • Bundle-Version: Dient zusammen mit dem symbolischen Namen als eindeutige ID. Default “0.0.0” • Bundle-Classpath: Listet alle Verzeichnisse und eingebettete JARs auf, die den lokal Klassenpfad des Bundles bilden wird. Default “.” • Import-Package: Listet die Abhängigkeiten in Form von Package-Namen auf • Export-Package: Listet die öffentliche Schnittstelle in Form von Package-Namen auf 3.2 OSGi-Grundlagen 15 Jedes Bundle innerhalb eines OSGi Frameworks kann während seiner Laufzeit in verschiedene Zustände wechseln. Der nächste Abschnitt beschreibt die verschiedene Zustände, die ein Bundle durchlaufen kann. 3.2.2.2 Lebenszyklus eines Bundles Ein Bundle kann sechs Zustände annehmen. Bei der Installation wird dem Bundle eine eindeutige ID vom Typ Long zugewiesen und wird in den Zustand INSTALLED versetzt. Das Bundle wird dann in dem lokalen Cache des OSGi-Framwork abgelegt. Bevor das Abbildung 6: Lebenszyklus eines Bundles Bundle gestartet werden kann, versucht das Framework alle Abhängigkeiten zu anderen Bundles aufzulösen. Das Bundle wird dann in den Zustand RESOLVED automatisch versetzt, wenn alle deklarierte Abhängigkeiten aufgelöst werden können. Falls mehrere passende Abhängigkeiten vorliegen, werden die mit der höchsten Version verwenden. Nur Bundles im Zustand RESOLVED können bereits verwendet werden. Wenn ein Bundle einen Activator spezifiziert, wird das Framework beim Start versuchen, dies zu starten, indem dessen start()-Methode aufgerufen wird. Beim Starten wird das Bundle zunächst in den Zustand STARTING versetzt. Wenn ein Activator spezifiziert ist und die start()-Methode nach einem Aufruf erfolgreich zurückkehrt, wird das Bundle auf ACTIVE gesetzt. Aus performancegründen kann der Aufruf der start()-Methode solange verzögern, dass das Bundle solange im Zustand STARTING verbleibt, bis zum ersten Mal eine Klasse aus 3.2 OSGi-Grundlagen 16 dem Bundle geladen wird. Beim Stoppen geht das Bundle in Zustand STOPPING über. Wenn ein Activator spezifiziert ist, wird dessen stop()-Methode aufgerufen und wenn diese erfolgreich zurückkehrt, wird das Bundle auf RESOLVED gesetzt. Bei der Desinstallation geht es zunächst in den Zustand UNINSTALLED über. Wenn das Bundle keine Packages exportiert, die auch verwendet wurden, wird es sofort aus dem Cache des OSGi Frameworks gelöscht. Andernfalls bleiben die Package-Exports bis zu einem Neustart des Frameworks erhalten. Dies Verhalten garantiert, dass durch das Deinstallieren eines Bundles nicht alle abhängigen Bundles automatisch funktionsunfähig werden. Abstrakt gesehen, ist die OSGi-Spezifikation in zwei logische Hälfte geteilt: Das OSGiFramework und das OSGi Service Model. Das OSGi-Framework bildet den Kern der OSGi Service Platform. Es ermöglicht die Bereistellung von erweiterbaren und herunterladbare Modulen (bundles). Das Framework ist verantwortlich für die Verwaltung von Bundles auf einer dynamischen und skalierbaren Art und Weise. Es steuert den Lebenszyklus von Bundles; dies beinhaltet insbesondere das Hinzufügen, Entfernen, Starten und Stoppen zur Laufzeit von Bundles. Die OSGi Laufzeit und installierten Bundels befinden sich in einer einzigen JVM. Die Ausführung mehrerer Anwendungen in der gleichen JVM hat einige Vorteile: Sie steigert die Leistung, minimiert den Speicherbedarf und ermöglicht eine effiziente Kommunikation zwischen Anwendungen. 3.2.3 Deklarative Services Declarative Services bietet ein Programmiermodell, welches den Umgang mit dynamischen Services vereinfacht. Das Zentrale Konzept in der Deklarative-Service-Spezifikation ist das Konzept der Serive Components. Ein Service Component besteht aus einer implementierenden Klasse, der Komponentenklasse, und einer Komponentenbeschreibung in Form eines XML-Dokumentes: • Eine Komponentenklasse: ist eine einfache Java-Klasse, die optional CallbackMethoden definieren kann, mit denen bei der Aktivierung und bei der Deaktivierung einer Komponente beliebige Aktionen ausgeführt werden können. • Die Komponentenbeschreibung beschreibt eine Komponente mit ihren Abhängigkeiten zu anderen Services in Form eines XML-Dokumentes. Zusätzlich kann angegeben werden, ob eine Komponente selber Services über die Service Registry bereitstellt. 3.2 OSGi-Grundlagen 17 Die Erzeugung von Komponenteninstanzen und die Verwaltung deren Lebenszyklus erfolgt durch die Service Component Runtime(SCR). Komponentenbeschreibungen können über sog. Component Properties parametrisiert werden. Component Properties können direkt in der Komponentenbeschreibung angegeben werden. Alternativ können sie aber auch über Component Factories zur Laufzeit gesetzt werden[14]. Mit Deklarativen Services ist es möglich, den Speicherbedarf einer Anwendung zu senken, da Bundles erst dann gesartet werden, wenn diese benötigt werden. Die OSGi Service Platform ist eine reine Spezifikation. Mittlerweile gibt es verschiedene Implementierungen davon. Für diese Arbeit wird Apache Felix [12] der Apache Software Foundation benutzt, weil es eine bessere Unterstützung für Android-Geräte anbieten. Die Bundle werden getrennt entwickelt und in einem Remote-HTTP-Repository gespeichert. Die Bundle werden erst nach einer erfolgreichen Abfrage bereitgestellt. Hierzu wird ein Remote-Repository als REST Web Service entwickelt. 3.3 REST Web Service Representational State Transfer (REST) ist kein definierter standard, sondern ein von Roy Thomas Fielding in seiner Dissertation[11] beschriebener Architekturstil für vertailte Anwendungen, der im Bereich der Webservices13 zunehmend an Bedeutung gewinnt. REST basiert auf den prinzipien des World Wide Web. Innerhalb einer Anwendung bietet ein Server adressiertbare Ressourcen. Clients und Server kommunitieren durch die Sendung von Anfragen und Antworten in der Form von Repräsentationen von Ressourcen. REST ist ressourcenzentriert. Mit jeder Abfragen wird eine Ressource entweder erstellt, aktualisiert, gelöscht oder seine Repräsentation abgefragt. Eine Ressource ist die Kernabstraktion einer Information in REST. Jede Information oder Datensatz kann eine Ressource sein. 3.3.1 Grundprinzipien Eine REST-Konforme Anwendung soll nach folgenden Prinzipien entworfen werden: • Client-Server: Der Client-Server-Architekturstil ist der Architekturstil, der eine REST-konforme Anwendung aufweisen soll. Dadurch wird das sogenannte Separation of Concerns-Prinzip[8], welches die Trennung von Zuständigkeiten vorschreibt, 13 Ein Webservice ist ein Dienst, der über ein Netzwerk erreichbar ist und über zugängliche Schnittstellen zu seinen Funktinalitäten verfügt. 3.3 REST Web Service 18 verwendet. Dadurch reduziert sich die Komplexität des Servers, da die dabei Komponenten einfach gehalten werden können. • Zustandlosigkeit: Die Client-Server-Kommunikation ist zustandslos. Das heißt, dass eine Anfrage alle benötigten Informationen enthalten muss, die zu seiner Bearbeitung nötig sind. Dabei werden Sitzungen ausschließlich clientseitig verwaltet. Ein Vorteil der Zustandslosigkeit ist, dass der Server sich nicht die SessionInformationen vieler Clients merken muss. • Cachefähigkeit: Um die Netzwerklast zu minimieren, kann ein Cache eingesetzt werden. • Einheitliche Schnittstelle: Ein wesentliches Aspekt, in dem sich REST-Systeme von anderen netzwerkbasierten Architekturstilen unterscheidet, ist die einheitliche Schnittstelle zwischen den Komponenten. Die Schnittstelle muss eine Teilmenge folgender Standardmethoden bereitstellt: – GET fragt eine Repräsentation einer Ressource ab. – POST erstellt eine neue Ressource. – PUT ändert eine Ressource, wenn ihre URI bekannt ist. Falls sie noch nicht existiert, wird eine neue Ressource erstellt. – DELETE löscht eine gegebene Ressource. – HEAD fragt Metadaten zu einer Ressource ab. – OPTIONS gibt die Methoden und Eigenschaften zurück, die unterstützt werden. Um die Forderung nach einer Einheitlichen Schnittstelle zu halten, stützt sich REST auf folgende Elemente: – Eindeutig identifizierbare Ressourcen: Ein grundlegendes Konzept von REST ist, dass eine Ressource eine eindeutige Kennung (URI) haben muss. Sie wird verwendet, um diese Ressource abzurufen. Der Bezeichner muss eindeutig sein und ausreichende Informationen tragen, damit die Ressource lokalisiert werden kann. – Verschiedene Repräsentationen der Ressourcen: Repräsentationen sind Darstellungen einer Ressource in einem definierten Format. Jede Ressource kann mehrere Repräsentationen haben. Das Ausmachen des Formats, welches vom Server geliefert wird, erfolgt durch eine Anfrage des Clients. 3.3 REST Web Service 19 4 Konzeption In diesem Kapitel wird auf Basis der Erkenntnisse der vorhergehenden Kapitel die Konzeptionelle Umsetzung der Zielanwendung präsentiert. Hierfür wurde auf eine Client-Server Architektur zurückgegriffen. Die Kommunikation zwischen Client und Server erfolgt auf Basis des REST-Architekturstils. Mit Hilfe von Erkenntnissen aus den Grundlagen werden Entwurfsentscheidungen erläutert und begründet. 4.1 Konzeption Das hier implementierte Anpassungsmechanismus lässt sich in drei Bestandteile untergliedern, die jeweils einzeln behandelt werden. • Integration des OSGi-Frameworks in Android • Entwurf des Remote-Repositorys • Kommunikation mit dem Remote-Repository Abbildung 7: System-Übersicht Die Abbildung 7 zeigt das gesamte System. Hier wird durch die einzelnen abgetrennten Komponenten deutlich gemacht, wo eine bestimmte Funktionalität umgesetzt wurde. Auf der untersten Ebene befindet sich myHealthHub. Es ist das System, dass angepasst wird. 20 Der Pfeil deutet darauf hin, dass das Herunterladen, Starten und Stoppen einer Transformation von myHealthHub eingeleitet wird. Die Schicht auf die, der Pfeil gerichtet ist, beinhaltet Dienste, die zur Ausführung der gewünschten Funktionalitäten notwendig sind. Apache Felix dient hier als Container für die Transformationen. Die Transformationen werden als OSGi-Bundles ausgeliefert. Ihre Funktionalitäten werden in Form von OSGi-Services dem System zur Verfügung gestellt. Die Transformationsverwaltungsschicht kümmert sich um die Kommunikation mit dem Remote-Repository und die Installation einer neuen Transformation. Sie führt auch Buch über die im System befindlichen Transformationen. Das konkrete Starten und Stoppen einer Transformation wird an Apache Felix delegiert. Implementierte Transformationen werden auf einem Remote-Repository abgelegt und nach erfolgreicher Abfrage geliefert. Das HTTP-Protokoll wird hierfür verwenden. Im nächsten Teil wenden wir uns der Integration des OSGi-Frameworks in Android zu. 4.1.1 Integration des OSGi-Frameworks in Android Das OSGi-Framework ist ein Modul-System und Service-Plattform für die Programmiersprache Java. Mit OSGi können Anwendungen oder Komponenten entfernt installiert, gestartet, gestoppt, aktualisiert und deinstalliert werden, ohne dass ein Neustart des Systems erforderlich ist. Obwohl die Dalvik VM - im Gegensatz zur Java VM - auf einer Register-Architektur basiert und keinen Java-Bytecode verarbeitet, sondern Android-eigenen DEX-Bytecode ausführt, können nahtlos vorhandenen Java-Code und Bibliotheken in Android integriert werden. Sie müssen lediglich in Dalvik-Bytecode umgewandelt werden. Da das OSGiFramework selbst und die Bundles einfach nur JAR-Dateien (mit einigen zusätzlichen Manifest-Header) sind, können sie auch in Android verwendet werden. Es klappt aber nicht immer. Das Problem liegt daran, es bei früheren Versionen von Android keine offizielle Methode zum dynamischen Nachladen von Klassen gibt. Apache Felix bietet eine für die Entwickler transparente Lösung. Das Framework ist nämlich seit Version 2.0.0 ohne Einschränkungen auf Android lauffähig. Apache Felix wurde auch ausgewählt, weil es mehr tragbar ist und besser geeignet für Embedded-Hardware-Geräten. Das komplette Framework kann in Form eines JAR-Archives als Bibliothek in eine Android-Anwendung eingefügt werden. Dadurch lässt sich eine Instanz der Klasse Framework von Felix konfigurieren, erzeugen und starten. 4.1 Konzeption 21 Nachdem die konzeptionelle Integration des OSGi-Frameworks in Android behandelt wurde, ist es wichtig, sich auch mit der konzeptionellen Interaktion zwischen OSGi-Bundles und Android zu beschäftigen. 4.1.1.1 Interaktion zwischen OSGi-Bundles und Android Wie in Abbildung 8 gezeigt wird, werden die Plugins (hier Transformationen genannt) von Apache Felix verwaltet. Damit die Plugins mit Android interagieren können, wird die Klasse Context von Android über die OSGi-Komponente Service-Registry als OSGiService veröffentlicht. Dadurch kann sie von allen Transformationen bezogen werden, um Intents zu empfangen (durch die Registrierung beim ersten Start eines BroadcastReceivers) und versenden. Um die Integration von Transformationen in myhealthhub einfach zu Abbildung 8: Felix in Android gewährleisten, wurde der deklarative Einsatz von OSGi-Services ausgewählt. Damit kann ein Bundle mit den jeweiligen implementierten Diensten und Abhängigkeiten automatisch von dem OSGi-Framwork verwalten werden. 4.1.2 Remote-Repository Die Aufgaben des Remote-Repositories liegen darin, die Transformationen aufzunehmen und sie nach Abfrage zu liefern. Hierfür stellt das Remote-Repository Ressourcen zur Verfügung. Da es als eines RESTful Web Services konzipiert wurde, ist der Einsatz eines servlet-Containers14 . unerlässlich. Betrieben wird der Server mithilfe von Jetty15 . Jetty 14 15 Ein Server, der die Servlet-Spezifikation implementiert http://jetty.codehaus.org/jetty/ 4.1 Konzeption 22 lässt sich im Vergleich zu enderen Servlet-Containern leicht einbetten. Damit eine Transformation heruntergeladen wird, muss mit dem Server (RemoteRepository) kommuniziert werden. Im nächstem Abschnitt soll die konzeptionelle Realisierung der Kommunikation mit dem Server - auch als Remote-Repository genannt behandelt. 4.1.3 Kommunikation mit dem Remote-Repository Die Basisvoraussetzung zur Entwicklung verteilter Anwendungen auf Mobilen Geräten sind schon heute erfüllt: Die heutigen Smartphones sind mit Technologien ausgestattet, die sie - unter anderem durch eine hohe Konnektivität und ausgezeichnete Geschwindigkeit - leistungsfähig machen. Die Kommunikation mit dem Remote-Repository erfolgt nach REST-Prinzipien auf Basis von HTTP. In einer REST-konform entworfenen Anwendung tauschen Clients und Server Darstellungen von Ressourcen16 aus, indem eine standardisierte Schnittstelle und ein Protokoll verwendet werden. REST zwingt nicht den Einsatz eines spezifischen Protokoll als Applikationsprotokoll. Der Grund, warum HTTP ausgewählt wurde, liegt darin , dass das HTTP-Protokoll als Applikationsprotokoll in REST-basierten Anwendungen besser geeignet ist. HTTP ist einfacher zu handhaben und unterstützt unter anderem z.B die Manipulation von Ressourcen, die über URIs identifiziert werden. Außerdem ist HTTP Abbildung 9: Client-Server-Interaktion in REST ein ausgereiftes und weit verbreitetes Protokoll. Die Android-Plattform wird mit der HttpComponents-Bibliothek von Jakarta Commons ausgeliefert. Die Bibliothek erleichtert den Umgang mit dem HTTP-Protokoll. Die Daten werden dabei im JSON-Format übertragen. JSON ist ein leichtgewichtiges und einfach zu bedienendes Datenaustauschformat mit welchem sämtliche Daten zwischen Client und Server ausgetauscht werden können. Die Daten werden hierbei als Schlüssel-Wert Paar übermittelt. Android verfügt auch über ein eingebaute Unterstützung für JSON. 16 Eine Ressource in diesem Fall ist alles, was wichtig genug ist, um referenziert zu werden. 4.1 Konzeption 23 Aus diesen Gründen hat sich das Format als eine überzeugende Alternative zu XML im Rahmen dieser Arbeit bewährt. Nachdem die Konzepte, auf denen diese Arbeit aufbaut, vorgestellt wurden, soll jetzt mit der Implementierung weitergemacht werden. 4.1 Konzeption 24 5 Implementierung In den folgenden Abschnitten wird die Implementierung des Erweiterungsmechanismus möglichst detailliert dargestellt. Im ersten Schritt werden die Tools, die für die Umsetzung benötigt wurden, kurz vorgestellt. Anschließend wird die Implementierung der Zielanwendung betrachtet. 5.1 Verwendete Tools Das Anpassungsmechanismus wurde mit Eclipse (Version 3.7) unter Verwendung des Android Software Development Kits (Android SDK) (Version 2.3.3) und Android Development Tool (ADT) entwickelt. ADT ist ein Android-Plugin für Eclipse. Als Build-Management-Tool wurde Apache Maven eingesetzt. Apache Maven lässt sich auch direkt aus Eclipse heraus bedienen. Dafür wurde das Plugin m2e (Aus Eclipse MarketPlace) installiert. 5.1.1 Software Development Kit Das Android Software Development Kit (SDK) ist eine Sammlung von Programmen zur Entwicklung von Android-Anwendungen. Damit bietet Google eine Reihe von Werkzeugen an, welche die Softwareentwicklung für Android vereinfachen kann. In diesem Abschnitt soll ein paar von diesen Tools, die nützlich für diese Arbeit waren, kurz vorgestellt werden. 5.1.1.1 Android Debug Bridge (adb) Die Android Debug Bridge ist eines der wichtigsten Werkzeuge für die Entwicklung von Android-Anwendungen. Damit lassen sich die inneren Abläufe eines Android-Gerätes direkt von der Konsole ablesen. Damit ist es auch möglich eine Android-Anwendung auf einem spezifischen Gerät bzw. Emulator zu installieren. Das Werkzeug erwies sich während der Implementierung als sehr nützlich. Damit konnten Probleme schnell erkannt und behoben werden. 5.1.1.2 dx-Tool Android Anwendungen sind größtenteils in Java geschrieben. Damit ein OSGi-Bundle in Android ausgeführt wird, es ist notwendig, sicherzustellen, dass das Bundle die Datei 25 classes.dex enthält. Das wird durch das dx-Tool erreicht. Das dx-Tool konvertiert die By- Abbildung 10: Umwandlungsfluss ein Bundles tecodes von Java (.class) in Android-Bytecode (.dex). Die Abbildung 10 veranschaulicht den Umwandlungsfluss eines Bundles. Nachdem die Java-Bytecode in einem JAR-Archiv gebündelt wurden, wird das dx-Tool darauf angewendet, um aus den compilierten Java-Klassen die Datei classes.dex zu erzeugen. Der Befehl dazu lautet: „dx –dex –keep-classes –output=output.jar input.jar“. „output.jar“ und „input.jar“ sollten gleich sein. Wenn die Option „–keep-classes“ nicht angegeben wird, werden alle class-Dateien in „input.jar“ mit einer Datei namens „classes.dex“ ersetzt. Somit gehen alle Class-Dateien verloren. Damit das JAR-Archiv aber weiterhin für Java-Anwendungen verwendet wird, muss die Option „–keep-classes“ verwendet werden. 5.1.2 Apache Maven Bei der Entwicklung einer Anwendung ist es wichtig, dass sich die Entwickler auf das notwendige konzentrieren, damit sie produktiv am Projekt arbeiten können. Dabei soll es nicht dazu kommen, dass sie von unnötigen Aufgaben wie die Konfigurationen von Bibliotheken abgelenkt werden. Mit Maven lassen sich solche Probleme durch verschiedene Automatisierungen lösen. Maven ist ein deklaratives Projektverwaltungswerkzeug, welches dem Entwickler beim Erstellungsprozess (Kompilierung, Testen und Verteilung) einer Anwendung hilfreich sein kann. Es dient zur Umsetzung der Buildautomatisierung für Java-Projekte. Die Philosophie hinter Maven heißt Konvention über Konfiguration. Das bedeutet, die Strukturen von Projekten müssen nicht definiert, sondern vorgegeben werden. Maven bietet mehrere Vorteile, die das Leben eines Entwicklers erleichtert kann. Dazu zählen zum Beispiel: • Verwaltung von Abhängigkeiten. • Kompilieren des Projektes. • automatische Ausführen von JUnit Tests. • Erzeugung der gewünschten Archivierung. 5.1 Verwendete Tools 26 Der Buildprozess in Maven wird in Phasen eingeteilt. Für diese Arbeiten waren die folgenden Phasen wichtig. • Compile (kompiliert sämtliche Java-Klassen) • Package (bildet das Archiv aus den kompilierten Klassen) • Install (kopiert das Archiv ins lokale Repository für die Referenz in anderen Projekten) Das wichtigste Element eines Maven-Projekts ist die Projektbeschreibungsdatei pom.xm. Dort werden zentral die Eigenschaften des Projekts konfiguriert. 5.1.2.1 pom.xml Lediglich die pom.xml-Datei wird von Maven bei seiner Ausführung interpretiert. Damit vertritt Maven einen deklarativen Ansatz, der sich von anderen verbreiteten Buildwerkzeugen unterscheidet. Drin sollten alle Informationen enthalten sein, welche für den gesamten Lebenszyklus des Projektes von Interesse sind. Dort werden Abhängigkeiten sowie Projektinformationen wie aktuelle Version, Archivierungstyp (JAR, war, . . . ) und viele mehr gespeichert. Der <dependencies />-Tag umfasst alle angegebenen Libraries , von denen das Projekt abhängt. Dabei kann auch mit angegeben werden, wie eine Abhängigkeit benutzt wird. Dadurch ist es möglich eine Bibliothek nur für eine bestimmte Phase zu benutzen. Um die Abhängigkeiten eines Projekts zu verwalten, verwendet Maven ein einziges lokales Verzeichnis, genannt Repository, in dem Bibliotheken zentral für alle Projekte abgelegt werden. Benötigte Bibliotheken werden selbstständig von einem Remote-Repository heruntergeladen und ins lokale Repository kopiert. Transitive Abhängigkeiten werden auch analysiert und aufgelöst. , 1 <dependency> 2 <groupId>o r g . OSGi</groupId> 3 <a r t i f a c t I d >o r g . OSGi . compendium</ a r t i f a c t I d > 4 <v e r s i o n >4.0.0 </ v e r s i o n > 5 <scope >pr ovided </scope > 6 </dependency> 7 <dependency> 8 <groupId>com . g o o g l e . Android </groupId> 9 <a r t i f a c t I d >Android </ a r t i f a c t I d > 10 <v e r s i o n > [ 2 . 3 . 3 , ) </ v e r s i o n > 11 <scope >pr ovided </scope > 5.1 Verwendete Tools 27 12 </dependency> 13 <dependency> 14 <groupId>de . tudarmstadt . dvs . myhealthhub . e v e n t s </groupId> 15 <a r t i f a c t I d >myHealthHubEvents</ a r t i f a c t I d > 16 <v e r s i o n >0.0.1 </ v e r s i o n > 17 <scope >pr ovided </scope > 18 19 </dependency> </d e p e n d e n c i e s > Listing 5.1: Definition von Abhängigkeiten Für die Transformators Das Listing 5.1 zeigt die deklarative Angabe von Abhängigkeiten, die bei der Entwicklung von Transformationen verwendet wurden. Die eindeutige Kennung einer Abhängigkeit wird via <artifactId></artifactId> bekanntgegeben. Via <scope></scope> wird den Gültigkeitssbereich einer Abhängigkeit angegeben. Abhängigkeiten verfügen über verschiedene Gültigkeitssbereiche (Scopes). Dazu gehören unter anderem: • provided: Die Abhängigkeit wird bei der Entwicklung des Projekts nur in der Kompilierungsphase benutzt. Später wird sie vom jeweiligen Laufzeitcontainer bereitgestellt und nicht mit ins Archiv eingebunden • test : Wird nur zum Testen des Projekts benötigt Es sind weitere Gültigkeitssbereiche vorhanden. Für diese Arbeit sind sie aber unwichtig. Die groupId ist eine Gruppierungsbezeichnung (ähnlich den Java-Package-Namen). Eine selbst erzeugte Bibliothek kann durch den Befehl „mvn install:install-file -Dfile=<pathto-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> Dpackaging=<packaging>“ ins Repository kopiert werden. , 1 <modelVersion >4.0.0 </ modelVersion> 2 <groupId>de . tudarmstadt . dvs . myhealthhub . t r a n s f o r m a t o r s 3 </groupId> 4 <a r t i f a c t I d >ECGtoHR</ a r t i f a c t I d > 5 <v e r s i o n >0.0.1 </ v e r s i o n > 6 <packaging >JAR</packaging > Listing 5.2: Beschreibung eines Maven-Projekts Der Archivierungstyp wird - wie ins Listing 5.2 gezeigt wird - via <packaging></packaging> angegeben. Maven verfügt über Projektschablonen. Diese Schablonen (auch Archetypes genannt) sind Maven-Projektvorlagen, die den strukturellen Aufbau eines Projekts bestimmen. Bei der Erstellung eines Archetypes werden bestimmte Abhängigkeiten eingebunden und Einstellungen gesetzt. Wenn keine bestimmte Schablone beim Erstellen eines Projektes angegeben wurde, wird ein „normales“ Java-Projekt erstellt. Dabei wird der Archivierungstyp auf 5.1 Verwendete Tools 28 „Jar“ gesetzt. Apache Maven bietet weitere Möglichkeiten, die während die Entwicklung dieser Arbeit nicht verwenden wurden. Nachdem die Verwendete Tools kurz vorgestellt wurde, soll im nächsten Schritt mit der eigentlichen Umsetzung weitergemacht werden. Im folgenden Abschnitt soll die Implementierung der Integration von Apache Felix in Android beschrieben werden. 5.2 Integration von Apache Felix in Android Die praktische Integration von Apache Felix in Android und die Verwaltung von Transformationen wurden in der Transformationsverwaltungsschicht (Abbildung 7) realisiert. Für die Integration von Apache Felix in Android wurden die Klassen FelixConfig, FelixService und Unzip entwickelt. Apache Felix wird mit Hilfe einer Java-Properties-Datei Abbildung 11: Klassen für die Integration von OSGi in Android configuriert. Dafür wird im Konstruktor der Klasse FelixConfig eine Instanz der Klasse java.util.Properties erzeugt und alle notwendige Properties gesetzt. 1 2 configProperties . setProperty ( 3 o r g . OSGi . framework . C o n s t a n t s .FRAMEWORK_STORAGE, 4 felixDeploymentDir . concat ( F i l e . separator ) 5 . concat ( Constants . felix_cache_dir ) ) ; 5.2 Integration von Apache Felix in Android 29 6 configProperties . setProperty ( 7 A u t o P r o c e s s o r .AUTO_DEPLOY_DIR_PROPERY, 8 f e l i x D e p l o y m e n t D i r . c o n c a t ( F i l e . s e p a r a t o r ) . c o n c a t ( " bundle " ) ) ; 9 c o n f i g P r o p e r t i e s . s e t P r o p e r t y ( BundleCache .CACHE_ROOTDIR_PROP, felixDeploymentDir ) ; 10 11 12 13 configProperties . setProperty ( C o n s t an t s . f e l i x _ e m b e d e e d _ p r o p e r t i e s , " t r u e " ) ; configProperties . setProperty ( " o r g . OSGi . framework . b o o t d e l e g a t i o n " , "∗" ) ; 14 15 16 configProperties . setProperty ( " f e l i x . auto . d e p l o y . a c t i o n " , " i n s t a l l , s t a r t " ) ; 17 configProperties . setProperty ( 18 " o r g . OSGi . framework . system . p a c k a g e s . e x t r a " , 19 Android_PACKAGES_FOR_EXPORT) ; Listing 5.3: Konfiguration des Apache Felix Frameworks Das Listing 5.3 zeigt einen Ausschnitt aus der Klasse FelixConfig. Die offizielle Felix Webseite17 bietet eine ausführliche Erklärung über die einzelnen Properties. Bevor Apache Felix gestartet wird, müssen einige Bundles vorinstalliert werden. Der Ort wird in der Properties-Datei (im Listing 5.3 in der Zeile 7) angegeben. Es sind die Bundles: • org.apache.felix.scr-1.0.9-SNAPSHOT • myHealthHubEvents • org.apache.felix.configadmin-1.2.4 • org.apache.felix.log-1.0.0 • org.apache.felix.shell-1.0.2 Das Bundle org.apache.felix.scr-1.0.9-SNAPSHOT ermöglicht den Einsatz von OSGi declarative Services. Das Bundle myHealthHubEvents enthält alle Event-Klassen, die für die Kommunikation in myHealthHub in Verwendung kommen. Alle Transformationen importieren die Paketen, die dieses Bundle exportiert. Sein Rolle ist es, die EventKlassen zur Laufzeit zur Verfügung zu stellen. Die Bundles org.apache.felix.shell-1.0.2, org.apache.felix.configadmin-1.2.4 und org.apache.felix.log-1.0.0 waren für Testzwecke benutzt worden. Nachdem alle diese Bundles mit dem dx-Tools bearbeitet wurden, wurden sie gezippt und als Android-Ressource ins Unterverzeichnis /res/raw eingelegt. Beim Start der Anwendung wird der Android-Service FelixService gestartet. Der erzeugt 17 http://felix.apache.org/site/apache-felix-framework-configuration-properties.html 5.2 Integration von Apache Felix in Android 30 eine Instanz der Klasse Unzip. Die Instanz liest die ins /res/raw eingelegte ZIP-Datei und entpackt sie in den Ordner, der im Konstruktor angegeben wurde. Mit Hilfe der Klasse FelixConfig wird eine Instanz der Klasse Framework (Aus dem Felix-Frameworks) konfiguriert und gestartet. Services in OSGi sind hochdynamisch. Sie werden bei der Aktivierung eines Bundles erzeugt, registriert und bei der Deaktivierung abgebaut. Bei Änderungen am Zustand eines Bundles generiert das Framework Events, die auf einfacherweise mit Hilfe einer Implementierung der ServiceListener-Schnittstelle abgefangen werden können. Über eine Instanz der Klasse BundleContext können ServiceListeners angemeldet werden. Eine Instanz der Klasse BundleContext ist nur Verfügbar, erst wenn das Framework bereit konfiguriert und initialisiert wurde. Nachdem eine Instanz des Frameworks gestartet wurde, wird eine anonyme Implementierung der ServiceListener-Schnittstelle registriert. Alternative Ansätze sind hier möglich. 1 2 f e l i x F r a m e w o r k . getBundleContext ( ) . a d d S e r v i c e L i s t e n e r ( new S e r v i c e L i s t e n e r ( ) { 3 4 @Override 5 public void serviceChanged ( ServiceEvent event ) { 6 ServiceReference s e r v i c e R e f e r e n c e = event . g e t S e r v i c e R e f e r e n c e ( ) ; 7 S t r i n g transformatorName = ( S t r i n g ) s e r v i c e R e f e r e n c e . g e t P r o p e r t y ( C o n s t a n t s . transformatorName ) ; ..... 8 9 }) ; Listing 5.4: Registrierung eines ServiceListeners in OSGi Das Listing 5.4 zeigt wie die Registrierung erfolgt. Alle Informationen, die in „component.xml“ angegeben wurden, sind zur Laufzeit über eine Instanz der Klasse ServiceReference erhältlich. Alle Transformationen deklarieren eine Abhängigkeit zu einer Instanz der Klasse Context von Android. Damit diese Abhängigkeit zur Laufzeit aufgelöst wird, muss Instanz dieser Klasse als Service registriert werden. Das Listing 5.5 zeigt wie das zustandekommen kann. 1 2 3 Hashtable<S t r i n g , S t r i n g > p r o p e r t i e s = new Hashtable<S t r i n g , S t r i n g >() ; p r o p e r t i e s . put ( " p l a t f o r m " , " Android " ) ; 4 f e l i x F r a m e w o r k . getBundleContext ( ) . r e g i s t e r S e r v i c e ( 5 Context . c l a s s . getName ( ) , g e t A p p l i c a t i o n C o n t e x t ( ) , p r o p e r t i e s ) ; Listing 5.5: Registrierung des Android Context als OSGi Service 5.2 Integration von Apache Felix in Android 31 Jede Komponente wird mindestens über eine Schnittstelle und seine Implementierung beschrieben. Das wird hier mit Context.class.getName() und getApplicationContext() erreicht (aus Listing 5.5). 5.3 Erstellung einer Transformation OSGi APIs sind mächtig, aber nicht immer einfach zu verwenden. Denn das Anbieten und Konsumieren von Diensten auf programmatischem Wege ist komplex und fehleranfällig. Deklarative Services bieten einen deklarativen Ansatz, um die Entwicklung von Komponenten zu vereinfachen. Dadurch wird das Konzept der Komponente auf der Abstraktionsebene der Dienste eingeführt. In der Datei component.xml wird eine Komponente beschrieben mit: • Eindeutiger Name der Komponente. • Dienste, die durch sie angeboten werden. • Dienste, die sie konsumiert. • Kardinalität der konsumierten Dienste. Das Listing 5.6 zeigt wie die ECGtoHR-Transformation (wandelt eines ECG-Streams in Heart Rate um) beschrieben wurde. 1 <?xml v e r s i o n=" 1 . 0 " e n c o d i n g="UTF−8"?> 2 <components xmlns : s c r=" h t t p : / /www. OSGi . o r g / xmlns / s c r / v1 . 0 . 0 "> 3 <!−− t r a n s f o r m a t i o n Component −−> 4 <s c r : component e n a b l e d=" t r u e " immediate=" t r u e " 5 name="ECGtoHR"> 6 <!−−Component C l a s s name −−> 7 <i m p l e m e n t a t i o n 8 c l a s s=" de . tudarmstadt . dvs . myhealthhub . t r a n s f o r m a t i o n . e c g t o h r . ECGtoHR" /> 9 10 11 12 <!−− s a m p l e t r a n s f o r m a t i o n S e r v i c e d e s c r i p t i o n −−> < s e r v i c e s e r v i c e f a c t o r y=" f a l s e "> <p r o v i d e i n t e r f a c e=" de . tudarmstadt . dvs . myhealthhub . t r a n s f o r m a t i o n . e c g t o h r . I T r a n s f o r m a t i o n "/> 13 </ s e r v i c e > <!−− S e r v i c e r e g i s t r a t i o n p r o p e r t i e s −−> 14 <p r o p e r t y name=" transformatorName " v a l u e="ECGtoHR" /> 15 <p r o p e r t y name=" s o u r c e " v a l u e=" de . tudarmstadt . dvs . m y H e a l t h A s s i s t a n t . Event . Reading . P h y s i o l o g i c a l . C a r d i o v a s c u l a r .ECG. ECGStream" /> 5.3 Erstellung einer Transformation 32 16 <p r o p e r t y name=" d e s t i n a t i o n " v a l u e=" de . tudarmstadt . dvs . m y H e a l t h A s s i s t a n t . Event . Reading . P h y s i o l o g i c a l . C a r d i o v a s c u l a r .ECG . HeartRate " /> 17 <!−− P r e f e r e n c e s S e r v i c e dependency d e s c r i p t i o n −−> 18 <r e f e r e n c e name=" Android . c o n t e n t . Context " i n t e r f a c e=" Android . c o n t e n t . Context " 19 c a r d i n a l i t y=" 1 . . 1 " p o l i c y=" dynamic " 20 bind=" bindAndroidContext " 21 unbind=" unbindAndroidContext " /> 22 23 </ s c r : component> </components> Die „Service registration properties“ sind Verwaltungsinformationen. Via <reference /> wird der konsumierte Dienst angegeben. Die Implementierung der Deklarative Services in Apache Felix erfolgt durch das Bundle org.apache.felix.scr. Es kümmert sich zur Laufzeit darum: • Angebotene Dienste bei der Service Registry zu registrieren • Beim Stoppen die angebotenen Dienste zu deregistrieren • Die konsumierten Dienste an die bind/unbind-Methoden zu übergeben Die Strukture des Transformation-Projekts (ECGtoHR) wurde mit Apache Maven erstellt. In diesem Fall ein Maven-Projekt mit „JAR“ als Archivierungstyp. Sehr wichtig Abbildung 12: Struktur des ECGtoHR-Transformationsprojekts sind die Methoden bindAndroidContext und unbindAndroidContext. Sie werden beim Starten bzw Stoppen eines Bundles aufgerufen. Mit kleinen Änderungen können andere Transformationen erstellt werden. 5.3 Erstellung einer Transformation 33 5.3.1 Verwaltung von Transformators Für die Verwaltung von Transformators wurde die Datenbank SQLite eingesetzt. Die Struktur der Datenbank wird in der Klasse SqlLiteHelper (Listing 5.7)beschrieben. 1 p u b l i c s t a t i c f i n a l S t r i n g COLUMN_ID =" i d " ; 2 p u b l i c s t a t i c f i n a l S t r i n g COLUMN_BUNDLE_ID = " b u n d l e I d " ; 3 p u b l i c s t a t i c f i n a l S t r i n g COLUMN_TRANSFORMATOR_NAME = "name" ; 4 p u b l i c s t a t i c f i n a l S t r i n g COLUMN_TRANSFORMATOR_DESTINATION = " d e s t i n a t i o n " ; Listing 5.6: Die Spalten der Datenbank Wie im Abschnitt 5.3 vorgestellt wurde, müssen Komponenten einen eindeutigen Name haben. Die Spalte „name“ wurde dafür definiert. Alle Bundels besitzen nach dem Start auch eine eindeutige Identifikationsnummer. Die Identifikationsnummer wird verwendet, um eine Transformation zu starten bzw stoppen. In der Spalte „destination“ wird das Transformationsergebnis (der SubskriptionsTyp) einer Transformation aufgenommen. Das ist auch im Moment eindeutig. Alle diese Informationen werden von der anonymen Implementierung der ServiceListener-Schnittstelle in der Klasse FelixService beim Start einer Transformation an den TransformationManager weitergeleitet. Dort werden sie mit Hilfe der Klasse TransformatorsDataSource persistiert. Für die Abfrage eines Transformator wird der SubskriptionsTyp mitgesendet. Mit dieser Information wird die Klasse TransformatorsDataSource über die Methode getTransformatorBySubscription (Listing 5.8), abgefragt, ob es schon einen Transformator für den SubskriptionsTyp gibt. 1 Log . i (TAG, " q u e r i n g f o r a t r a n s f o r m a t o r : " + s u b s c r i p t i o n ) ; 2 S t r i n g [ ] whereArguments = { s u b s c r i p t i o n } ; 3 Cursor c u r s o r = d a t a b a s e . query ( S q l L i t e H e l p e r .TABLE_TRANSFORMATORS, 4 S q l L i t e H e l p e r . columns , " d e s t i n a t i o n = ? " , whereArguments , n u l l , n u l l , 5 null ) ; 6 Transformator trans = cursorToTransformator ( c u r so r ) ; 7 return trans ; Listing 5.7: Eine Datenbankabfrage 5.4 Umsetzung des Remote-Repositorys Als letzte Komponente soll die Implementierung des Remote-Repositories behandelt werden. Es ist dafür zuständig, dem System die Entwickelten Transformationen bereitzustel5.4 Umsetzung des Remote-Repositorys 34 len. Da es ist beim Remote-Repository um eine HTTP-basierte Anwendung handelt, muss ein Webserver eingesetzt werden. Hierfür wurde Apache Jetty verwendet. 5.4.1 Struktur des Projekts Für die Implementierung des Remote-Repositorys wurde wieder Apache Maven Als Build-Management-Tool eingesetzt. Für dieses Projekt wurde die Projektvorlage „MavenArchetypen-Webapp“ von Maven genutzt, um die Struktur des Projekts zu erstellen. Die Abbildung 13: Struktur des Remote-Repository-Projekts Abbildung 13 zeigt die Struktur des Projekts. Wichtig hier ist die Datei web.xml. Drin sind ein paar Angaben, die für die Konfiguration des Webservers benutzt wurden. 5.4.2 Konfiguration des Webservers Jetty wurde ausgewählt, weil er sich leicht in eine Anwendung einbetten lässt. Für seine Konfiguration wurde die Klasse JettyWebServer geschrieben. 1 2 p r i v a t e f i n a l s t a t i c S t r i n g webAppDir = " s r c /main/webapp/ " ; p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) throws E x c e p t i o n { 3 4 JettyWebServer j e t t y W e b S e r v e r = new JettyWebServer ( ) ; 5 jettyWebServer . s t a r t S e r v e r ( ) ; 6 7 } 8 p u b l i c v o i d s t a r t S e r v e r ( ) throws E x c e p t i o n { 5.4 Umsetzung des Remote-Repositorys 35 9 10 S e r v e r s e r v e r = new S e r v e r ( 8 0 8 0 ) ; 11 s e r v e r . setThreadPool ( createThreadPool ( ) ) ; 12 s e r v e r . addConnector ( c r e a t e C o n n e c t o r ( ) ) ; 13 server . setHandler ( createHandlers () ) ; 14 s e r v e r . setStopAtShutdown ( t r u e ) ; 15 server . start () ; 16 server . join () ; } 17 Listing 5.8: Eine Datenbankabfrage Wie das Listing 5.9 zeigt, besitzt die Klasse eine „main“-Methode. Damit lässt der Webserver als eine „normale“ Java-Anwendung starten. Das Listing zeigt außerdem wie eine Instanz des Servers erzeugt und konfiguriert wurde. Ein Server ist nur dann wichtig, wenn er Abfragen entgegennehmen kann. 5.4.3 Remote-Repository REST-konform Entwickelt JAX-RS ist das Java API für RESTful Web Services. Die JAX-RS-Spezifikation wird durch den Java Community Process (JCP) als Java Specification Request (JSR) 311 vorgeschlagen und ist ein Teil der Java EE 6[2]. JAX-RS baut auf Servlets18 auf. Die Referenz-Implementierung von JAX-RS ist Jersey[3]. Andere Implementierungen sind unter anderem Restlet[6], RESTEasy[5] und Apache CXF[1]. 5.4.3.1 REST mit Jersey Um den Server REST-konform zu entwerfen, wurde Jersey verwendet. Jersey ermöglicht die Entwicklung von RESTful Web Services mit der Java-Plattform durch den Einsatz von Annotationen. JAX-RS und Jersey folgen den REST-Prinzipien und deren Best Practices. Jersey ist formatunabhängig und unterstützt die Verwendung von XML, JSON und andere Dateiformate. Mit Jersey kann jede Java-Klasse als Ressource benutzt werden. Die Klasse muss lediglich mit Annotationen versehen werden. Die Java 5 Annotationen werden verwendet, um die URIs und die unterstützten HTTP-Methoden als einheitliche Schnittstelle zu definieren. Eine Abstimmung der Inhalte der angefragten Ressource erfolgt unter Verwendung von Annotationen. Annotationen werden auch verwendet, um Informationen aus einem HTTP-Request zu extrahieren. 18 Servlets sind Java-Klassen, die serverseitig ausgeführt werden 5.4 Umsetzung des Remote-Repositorys 36 Für diese Arbeit wurde die Klassse TransformatorsWebResources als Ressource verwendet. Das Listing 5.10 zeigt, wie die Klasse mit Annotationen versehen wurde. Die Methode getTransformator ist erreichbar über die URL: „http://<server-host>:<serverport>/transformators/query?jsonString=<parameter>“ Die richtigen Parameter müssen noch setzen werden. 1 @Path ( " / t r a n s f o r m a t o r s " ) 2 p u b l i c c l a s s TransformatorsWebResources { 3 4 @GET 5 @Produces ( MediaType . APPLICATION_JSON) 6 @Consumes ( MediaType . APPLICATION_JSON) 7 @Path ( " / query " ) 8 public String getTransformator ( @QueryParam ( " j s o n S t r i n g " ) S t r i n g j s o n S t r i n g R e q u e s t ) { 9 .... 10 11 } Listing 5.9: Beschreibung einer Ressource Damit das Ganze funktioniert muss Jersey konfiguriert und aktiviert werden. Das erfolgt auf deklarative Weise mit Hilfe der Datei web.xml. Das Listing 5.10 zeigt einen Ausschnitt aus dem Inhalt der Datei. 1 <s e r v l e t −name>J e r s e y REST S e r v i c e </ s e r v l e t −name> 2 <s e r v l e t − c l a s s >com . sun . j e r s e y . s p i . c o n t a i n e r . s e r v l e t . S e r v l e t C o n t a i n e r </ s e r v l e t −c l a s s > 3 <i n i t −param> 4 <param−name>com . sun . j e r s e y . a p i . j s o n . POJOMappingFeature</param−name> 5 <param−val ue >t r u e </param−val ue > 6 </ i n i t −param> 7 <i n i t −param> 8 <param−name>com . sun . j e r s e y . c o n f i g . p r o p e r t y . packages </param−name> 9 <param−val ue >de . tud . darmstadt . dvs . myhealthhub . t r a n s f o r m a t o r s . r e s t </ param−val ue > 10 </ i n i t −param> Listing 5.10: Jersey-Konfiguration In der Zeile 9 wird angegeben, wo sich die Ressourcen (Klassen mit Annotationen) befinden. Die notwendigen Bibliotheken wurden von Apache Maven installiert. 5.4 Umsetzung des Remote-Repositorys 37 5.4.4 Speicherung von Transformationen Die Transformationen werden im Filesystem des Servers gespeichert. Der Server führt Buch über die Verfügbaren Transformationen mit Hilfe einer Java-Properties-Datei. Drin werden die Namen der bekannten Transformationen aufgelistet. Wie eine Kommunikation mit dem Server (Remote-Repository) zustande kommen kann, wird im nächsten Abschnitt behandelt 5.5 Kommunikation mit dem Remote-Repository Jedes Mal, wenn der TransformationManager eine Anfrage nach einem unbekannten Transformator bekommt, wird WebRequestService durch das Senden eines Intents gestartet. In WebRequestService wird ein JSONObject erstellt und mit den Informationen aus dem Intent konfiguriert. Anschließend wird aus der JSONObject-Instanz einen JavaString erzeugt. Der String wird verwendet (Listing 5.11), um eine Http-Get-Abfrage an den Server zu senden. 1 Uri . B u i l d e r b = Uri . p a r s e ( b a s e U r l ) . buildUpon ( ) ; 2 b . path ( " / t r a n s f o r m a t o r s / query / " ) ; 3 b . appendQueryParameter ( " j s o n S t r i n g " , 4 transformatorRequestString ) ; 5 String urlRequest = b . build () . toString () ; 6 String serverResponse = null ; 7 8 H t t p C l i e n t h t t p C l i e n t = new D e f a u l t H t t p C l i e n t ( ) ; 9 10 try { 11 12 Log . i (TAG, " s e n d i n g a g e t r e q u e s t t o t h e s e r v e r " ) ; 13 14 HttpGet httpGet = new HttpGet ( u r l R e q u e s t ) ; 15 16 /∗ h e a d e r s ∗/ 17 httpGet . s e t H e a d e r ( " Accept " , " a p p l i c a t i o n / j s o n " ) ; 18 httpGet . s e t H e a d e r ( " Content −Type" , " a p p l i c a t i o n / j s o n " ) ; 19 20 HttpResponse r e s p o n s e = h t t p C l i e n t . e x e c u t e ( httpGet ) ; Listing 5.11: Senden einer Http-Get-Abfrage 5.5 Kommunikation mit dem Remote-Repository 38 Wenn die Abfrage erfolgreich war, wird die Antwort des Servers an FelixService weitergeleitet. Das geschieht durch das Versenden eines Android-Intents. Durch seines BroadcastReceivers empfangt FelixService die Nachricht. Die im base64 kodierte Transformation wird extrahiert, dekodiert und installiert. Wenn die Installation erfolgreich abgeschlossen wurde, wird der TransformationManager über die anonyme Implementierung der ServiceListener-Schnittstelle benachrichtigt. Nachdem die Konzepte und die Implementierung vorgestellt wurden, wird im nächsten Abschnitt die Abläufe beschrieben, die zum Herunterladen und Installation einer Transformation führen. 5.6 Installation einer Transformation In diesem Abschnitt werden die Schritte möglichst detailliert beschrieben, die zum Herunterladen bis zur Installation einer Transformation notwendig sind. Vor allem wird die Kommunikation zwischen den involvierenden Komponenten deutlich gemacht. 5.6.1 Ablauf Bevor eine Transformation abgefragt und installiert wird, muss ein Benutzer den Wusch nach einer bestimmten Art eines Ereignis ( z.B Herzfrequenz) äußert, dass das System zum Zeitpunkt der Anfrage selbst nicht liefert kann. myHealthHun basiert auf dem Anmelde-Versender-Prinzip. Das heißt: Jede AndroidAnwendung muss sich für einen bestimmten Event-Typ registrieren, bevor sie auch die gewünschten Informationen bekommen kann. Für jeden Event-Typ existiert eine eindeutige Klasse. Im Zuge einer Subskription prüft das System, ob es den Benutzer bedienen kann. Wenn es im Moment nicht der Fall ist, wird der TransformationManager beauftragt die passende Transformation zu suchen. Hierzu wird ein Event vom Typ „EventTransformationRequest“ gesendet. Der Event enthält neben der Subskription des Benutzer auch den Typ der Anfrage. Wenn es sich um das Starten einer Transformation geht, prüft der TransformationManager, ob er die Transformation schon kennt. Wenn es nicht den Fall ist, wird die Anfrage an WebRequestService weitergeleitet. Die hat nur die Aufgabe (Single-Responsibility5.6 Installation einer Transformation 39 Prinzip) , mit dem Remote-Repository zu kommunizieren. In der Klasse WebRequestService wird einen HTTP-GET-Request abgesetzt. Falls der Server die gesuchte Transformation finden kann, wird sie mittels base64 kodiert. Damit gewinnt man aus binären Daten eine Zeichenkette. Die String-Darstellung der Transformation wird im JSON-Format verpackt und geliefert. Die Antwort wird an den TransformationManger weitergeleitet. Dort wird die Transformation dekodiert und installiert. Wenn die Transformation gestartet werden könnte, wird ein Event an den Initiator der Abfrage gesendet. Es handelt sich nur die Abläufe einer Installation. Weitere Szenarien sind möglich. Die Abbildung 14 veranschaulicht die hier beschriebenen Abläufe. Abbildung 14: Installation einer Transformation 5.6 Installation einer Transformation 40 6 Fazit und Aussicht Dieses Kapitel fasst die gesamte Arbeit zusammen, die aus den Grundlagen, dem Entwurf und der Implementation der dynamischen Anpassung für myHealthHub besteht. Die Zusammenfassung soll außerdem eine abschließende Betrachtung des Themas geben. Weiterhin werden offene Punkte und mögliche weiterführende Arbeiten aufgeführt. 6.1 Fazit Der Ziel dieser Bachelorarbeit war die Entwicklung eines Anpassungsnechanismus für myHealthHub. Mit dem Anpassungsnechanismus sollte sich das System selbständig und dynamisch um neue Transformationen erweitern können. Das Mechanismus soll myhealthHub vor allem dabei helfen, seine Akzeptanz und Einsatzgebiete zu erhöhen. Durch die sorgfältige Auswahl verschiedener Technologien und Techniken hat diese Arbeit gezeigt wie eine dynamische dynamische Software auch in mobilen Geräten entstehen und eingesetzt werden kann. Die Dynamik des Systems ist vor allem dadurch gewährleisten, dass OSGi eingesetzt wurde. OSGi war ursprünglich für Heimautomationssysteme konzipiert worden. Die Mächtigkeit des Frameworks hat sich allein dadurch bewährt, daß es den besonderen Anforderungen an CPU und Speicher der dort häufig eingesetzten Embedded Devices gewachsen war. Das in dieser Arbeit entwickelte Mechanismus erfüllt alle grundlegenden Anforderungen, die gestellt wurden. Während der Entwicklung kam es zu keinem Zeitpunkt zu Konflikten zwischen den eingesetzten Technologien. Wichtig für das entwickeltes Anpassungsnechanismus war auch die Bereitstellung eines einfachen, modernen und leistungsfähigen Servers, der als Remote-Repository fungiert kann. Seine Rolle ist es, alle verfügbaren Transformationen zu speichern und sie nach Abfragen auszuliefern. Der Server wurde als RESTful Webservice entwickelt und als Transportprotokoll wurde HTTP verwendet. 6.2 Aussicht Was man noch machen würde, wäre die Kommunikation mit dem Remote-Repository zu verschlüsseln. Damit kann sichergestellt, dass die Integrität einer Transformation während der Übertragung nicht beeinträgtigt wird. 41 Abkürzungsverzeichnis EDI Electronic Data Interchange XML Extensible Markup Language 42 Literaturverzeichnis [1] Apache cxf. http://cxf.apache.org. [2] Javaee6 jax rs. http://java.sun.com/javaee/6/docs/tutorial/doc/giepu.html. [3] Jersey. https://jersey.dev.java.net. [4] Oha (open handset alliance). http://www.itwissen.info/definition/lexikon/ OHA-open-handset-alliance.html. [5] Resteasy. http://www.jboss.org/resteasy. [6] Restlet. http://www.restlet.org. [7] Openhandset Alliance. Android overview. http://www.openhandsetalliance.com/ android_overview.html. [8] derekgreer. Apache felix framework configuration properties. http://www. aspiringcraftsman.com/2008/01/art-of-separation-of-concerns/. [9] Michael Duvigneau. Konzeptionelle Modellierung von Plugin-Systemen mit Petrinetzen. PhD thesis, University of Hamburg, 2009. http://d-nb.info/1004294026. [10] R. Johnson E. Gamma, R. Helm and J. Vlissides. Design Patterns: Elements of Reusable Object-Ooriented Software. Addison Wesley, Massachussetts, 1994. [11] Roy Thomas Fielding. Architectural styles and the design of network-based software architectures. PhD thesis, University of California, Irvine, 2000. AAI9980887. [12] The Apache Software Foundation. Foundation, a.: Apache felix. http://felix.apache. org/. [13] Marko Gargenta. Einführung in die Android Entwicklung. O´REILLY, 2011. [14] Bernd Kolb Matthias Lübken Gerd Wütherich, Nils Hartmann. Die OSGI Service Platform. dpunkt.verlag GmbH, Ringstraße 19 69115 Heidelberg, 2008. [15] Jeff Kramer and Jeff Magee. The evolving philosophers problem: Dynamic change management. IEEE Trans. Softw. Eng., 16(11):1293–1306, November 1990. III [16] Yunhe Shi, Kevin Casey, M. Anton Ertl, and David. Gregg. Virtual machine showdown: Stack versus registers. ACM Trans. Archit. Code Optim., 4(4):2:1–2:36, January 2008. [17] Syed Hammad Khalid Banuri Sohail Khan, Shehryar Khan. Technical report on analysis of dalvik virtual machine class path library. http://imsciences.edu.pk/serg/ projects/easip/resources/. [18] Arif Wider. Komponentenorientierte anwendungsentwicklung auf der .net-plattform, Oct 2008. Literaturverzeichnis IV