Entwurf und Implementierung einer dynamischen

Werbung
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
Herunterladen