Entwicklung einer Steuerinstanz zur interaktiven Kopplung verteilter

Transcription

Entwicklung einer Steuerinstanz zur interaktiven Kopplung verteilter
Entwicklung einer Steuerinstanz zur
interaktiven Kopplung verteilter Geräte
Bernhard Wally
DIPLOMARBEIT
eingereicht am
Fachhochschul-Masterstudiengang
Digitale Medien
in Hagenberg
im Juni 2006
c Copyright 2006 Bernhard Wally
Alle Rechte vorbehalten
ii
Erklärung
Hiermit erkläre ich an Eides statt, dass ich die vorliegende Arbeit selbstständig und ohne fremde Hilfe verfasst, andere als die angegebenen Quellen
und Hilfsmittel nicht benutzt und die aus anderen Quellen entnommenen
Stellen als solche gekennzeichnet habe.
Hagenberg, am 22. Juni 2006
Bernhard Wally
iii
Inhaltsverzeichnis
Erklärung
iii
Vorwort
vii
Kurzfassung
viii
Abstract
ix
1 Einleitung
1.1 Problematiken . . . . . . . . . . . .
1.2 Ausblick . . . . . . . . . . . . . . . .
1.3 Abgrenzung . . . . . . . . . . . . . .
1.3.1 Unified Generic Control Point
1.3.2 Janus . . . . . . . . . . . . .
1.3.3 Smart Home Server . . . . .
1.3.4 Shaman . . . . . . . . . . . .
1.3.5 Socam . . . . . . . . . . . . .
1.3.6 Eigener Prototyp . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
2
2
3
3
4
4
4
4
5
2 Verteilte Systeme
2.1 Middleware . . . . . . .
2.1.1 CORBA . . . . .
2.1.2 Java RMI . . . .
2.1.3 .NET Remoting
2.1.4 XML-RPC . . .
2.2 Service-Plattformen . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
7
7
9
10
10
11
.
.
.
.
.
.
13
14
16
17
19
20
21
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3 Heterogene Systeme
3.1 Arten von Heterogenität . . . .
3.2 Methoden der Homogenisierung
3.3 OSGi . . . . . . . . . . . . . . .
3.3.1 Das OSGi-Framework .
3.3.2 Das OSGi-Bundle . . .
3.3.3 Dienste . . . . . . . . .
iv
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
INHALTSVERZEICHNIS
3.3.4
v
OSGi-Implementierungen . . . . . . . . . . . . . . . .
4 Anforderungen
4.1 Model . . . . . . . .
4.1.1 Komponenten
4.1.2 Kopplungen .
4.2 Control . . . . . . .
4.2.1 Komponenten
4.2.2 Kopplungen .
4.2.3 Schaltbild . .
4.3 View . . . . . . . . .
24
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
26
26
33
37
38
39
39
39
5 Technologieauswahl
5.1 Grafische Programmierwerkzeuge
5.1.1 Virtools Dev . . . . . . .
5.1.2 Max . . . . . . . . . . . .
5.1.3 vvvv . . . . . . . . . . . .
5.1.4 Fazit . . . . . . . . . . . .
5.2 Programmiersprache . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
40
40
40
43
45
46
47
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
49
51
51
55
58
60
61
61
64
66
70
73
73
76
79
83
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6 Umsetzung
6.1 Kern-Bundles . . . . . . . . . .
6.1.1 Component-Bundle . . .
6.1.2 Link-Bundle . . . . . . .
6.1.3 Converter-Bundle . . . .
6.1.4 Position-Bundle . . . . .
6.2 GUI-Komponenten . . . . . . .
6.2.1 GUI-Basis . . . . . . . .
6.2.2 Component Factories . .
6.2.3 Components und Links
6.2.4 Converters . . . . . . .
6.3 Erweiterungen . . . . . . . . .
6.3.1 Standard Ingredients . .
6.3.2 UPnP . . . . . . . . . .
6.3.3 Remote GUI . . . . . .
6.4 Szenario . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7 Fazit
86
7.1 Ergebnisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
7.2 Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
7.3 Schlussbemerkung . . . . . . . . . . . . . . . . . . . . . . . . 88
A Entwicklung der If-Component
89
INHALTSVERZEICHNIS
B Inhalt der CD-ROM
B.1 Diplomarbeit . . . .
B.2 Literatur . . . . . . .
B.3 Bilder und Grafiken
B.4 Ausführbare Dateien
B.5 Quelldateien . . . . .
B.6 Externe Bibliotheken
B.7 Abhängigkeiten . . .
B.8 Beispiel-Mappings .
B.9 Sonstige Dateien . .
vi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
92
92
92
93
93
93
94
95
95
95
Abkürzungsverzeichnis
96
Literaturverzeichnis
98
Vorwort
Der Entschluss, nach dem Bakkalaureats- ein Master-Studium in Hagenberg
anzuhängen, war schnell gefasst und stand eigentlich nie außer Frage. Nach
insgesamt fünf Jahren in Hagenberg ist meine Begeisterung für digitale Medien in keiner Weise gedämpft worden, und ich möchte mich auch in Zukunft
in diesem Themenbereich betätigen.
Das Studium wäre nicht ohne die Unterstützung meiner Eltern möglich
gewesen, die mir nicht nur finanziell unter die Arme griffen, sondern mir mit
viel Verständnis, unendlicher Geduld und ermutigenden Worten zur Seite
standen. Ich möchte ihnen an dieser Stelle meinen herzlichsten Dank aussprechen. Meinem Vater danke ich darüber hinaus für die vielen tausend
Kilometer die er meinetwegen zwischen Wien und Hagenberg zurückgelegt
hat, sowie für sein Engagement beim Korrekturlesen dieser Diplomschrift.
Auch meinen Freunden (allen voran meine liebe Anna) danke ich für ihre
Treue, die sie in den letzten fünf Jahren bewiesen haben. Jedesmal, wenn ich
in ihrem Kreise war, fühlte ich mich wohl und verstanden. Die geographische
Distanz, die uns trennte, machte jedes Treffen zu einem besonderen Erlebnis,
das ich ausgiebig genoss.
Meinem Projektpartner, Jakob Doppler, danke ich für zwei wunderbare
Jahre der Zusammenarbeit, in denen wir zu engen Freunden wurden. Gerne
und mit Wehmut denke ich an die vielen, vielen Tage zurück, in denen wir
gemeinsam in meinem Zimmer saßen und neue Ideen sponnen, einander mit
Technologie-Tipps versorgten und nebenbei viel Spaß hatten.
Zuletzt richtet sich mein Dank an meinen Diplomarbeits-Betreuer, DI
Dr. Christoph Schaffer, der mir auch schon als Projekt-Coach in vorangegangenen Semestern beratend zur Seite stand. Seine Ideen und kritischen
Anmerkungen leisteten einen wertvollen Beitrag zu dem Projekt, das in
dieser Arbeit vorgestellt wird. Er schaffte es immer wieder, meine Neugier
auf mir unbekannte Technologien zu lenken und erinnerte mich wiederholt
daran, auch komplexe Vorgänge nicht einfach hinzunehmen, sondern bewusst zu hinterfragen.
vii
Kurzfassung
Die Vernetzung des alltäglichen Lebens nimmt immer mehr zu. Die große
Zahl an netzwerkfähigen Endgeräten und deren unterschiedliche Anforderungen, hat auch zu einem Zuwachs an Netzwerktechnologien und deren
Kommunikationsprotokollen geführt. Um die damit verbundene zunehmende
Heterogenität in den Griff zu bekommen, werden Standards entwickelt, die
das Kommunizieren von im Netzwerk verteilten Geräten untereinander vereinfachen sollen.
In dieser Arbeit wird die Entwicklung von Torem erläutert, einer Applikation, die es ermöglicht, die Funktionalitäten verschiedener verteilter
Geräte zu nutzen, um andere verteilte Geräte zu steuern. Die Kopplung
der Geräte miteinander wird Technologie-übergreifend realisiert, sodass z. B.
eine Jalousie, die in ein Gebäudesteuerungs-System integriert ist, von einem
Drucksensor gesteuert werden kann, der selbst keine Möglichkeit hat, mit
der Jalousie direkt zu kommunizieren. Das Definieren der Kopplungen erfolgt über eine grafische Benutzeroberfläche, die diese Verbindungen auch
visualisiert.
Torem ist speziell auch für technisch nicht allzu versierte Personen ausgelegt, da die Netzwerkkommunikation komplett abstrahiert wird. Für den
Benutzer werden die Funktionen der verteilten Geräte als Funktionsblöcke
präsentiert, die miteinander verbunden werden können.
viii
Abstract
Computer networks are extraordinarily prevalent in today’s world. The increasing amount of network-capable devices has led to an increase in network technologies and their communication protocols, since different devices
define different requirements for networking. Standards are developed to
address the involved heterogeneity and to simplify communication among
distributed devices.
This paper discusses the development of Torem, an application that allows distributed devices to use functions of other distributed devices via
linking. The links are realized in a technology-independent manner so that
a sunblind integrated into a home automation system can be controlled by
a pressure sensor that could normally not communicate with the sunblind.
The creation of the links is accomplished using a graphical user interface
which is also responsible for visualizing the defined links.
Torem was specifically designed for use by less technologically inclined individuals, in that the underlying network communication is completly transparent to the user. The functions of the distributed devices are displayed as
building blocks that can be interconnected.
ix
Kapitel 1
Einleitung
Ihr Mobiltelefon piepst – eine neue Kurzmitteilung: Das Backrohr hat die
”
gewünschte Temperatur von 180◦ erreicht“. Sie gehen in die Küche, schieben
den Kuchenteig ins Rohr und aktivieren, zurück in ihrem Arbeitszimmer, die
elektronische Eieruhr. In 50 Minuten werden sie eine weitere Kurznachricht
erhalten, die sie daran erinnern soll, den Kuchen zu inspizieren und gegebenenfalls aus dem Rohr zu nehmen. Auch wenn sie nun in den Garten gehen
würden, auf den Kuchen würden sie mit Sicherheit nicht vergessen. Sie entscheiden sich jedoch, es sich in der Zwischenzeit ein wenig gemütlich zu
machen. Nachdem im Menü des Mobiltelefons der richtige Eintrag gefunden
ist, genügt ein weiterer Tastendruck und schon wird das Licht gedimmt, die
Stereo-Anlage beginnt in angemessener Lautstärke ihr aktuelles Lieblingsalbum abzuspielen und der Wasserkocher schaltet sich ein, um Teewasser zu
erhitzen.
Dieses Szenario zeigt eine mögliche Anwendung für die Steuerung verteilter Geräte in einem Haushalt. Die einzelnen Geräte werden je nach Typ über
drahtlose oder kabelgebundene Protokolle angesprochen und miteinander in
Bezug gesetzt. Doch nicht nur im Haushalt bietet sich eine solche Kopplung
von Geräten an. Auch bei örtlich ausgedehnten Multimedia-Installationen
gilt es, die verschiedenen Komponenten mit Informationen zu versorgen oder
von ihnen bereitgestellte Informationen auszulesen, um damit andere Geräte
anzusteuern. So könnte etwa eine Videokamera, beim Eingang einer Firma
installiert, einen Video-Beamer im Foyer mit Bilddaten versorgen, die von
einer dritten Komponente – im Foyer verteilte Drucksensoren – manipuliert
würden.
Wie ein solcher Aufbau auch konkret aussieht – bei der Verwendung
technologisch unterschiedlicher Komponenten, die miteinander über ein oder
mehrere Netzwerke kommunizieren sollen, stellen sich einige Probleme, die
es zu lösen gilt. Der nächste Abschnitt wird kurz darauf eingehen.
1
KAPITEL 1. EINLEITUNG
1.1
2
Problematiken
Verteilte Anwendungen sind im Gegensatz zu einer lokal laufenden Applikation mit zusätzlichen Problemstellungen konfrontiert. Es gilt etwa festzustellen, ob die benötigten Netzwerkressourcen überhaupt verfügbar sind.
Bei dynamisch erweiterbaren Netzwerken ist es wichtig herauszufinden, welche (kompatiblen) Komponenten zu einem gewissen Zeitpunkt im Netzwerk
vorhanden sind, und wie diese angesprochen werden können. Auch sind Strategien zu überlegen, wie man mit dem plötzlichen Wegfall einer Ressource
umgeht, und wie das System darauf reagiert, wenn die Ressource wieder
verfügbar wird. Diese Problemstellungen werden unter dem Begriff ver”
teilte Systeme“ zusammengefasst behandelt [28].
Doch es gibt auch andere Problematiken, die sich hauptsächlich aufgrund der unterschiedlichen Basistechnologien der einzelnen Komponenten
ergeben. Daten in einem IP1 -basierten Netzwerk lassen sich recht einfach
zwischen zwei oder mehreren Stationen austauschen. Auch zwischen Bluetooth2 -Geräten ist der Austausch von Daten spezifiziert. Doch um von einem
Bluetooth-Gerät auf eine Komponente in einem IP-basierten Netzwerk zugreifen zu können, bedarf es schon etwas komplizierterer Verfahren3 . Ein
aus unterschiedlichen miteinander verbundenen Netzwerken gebildetes Gesamtsystem nennt man auch heterogenes System“, wenn die Kommunika”
tion zwischen den verschiedenen Netzwerken nicht direkt von den jeweiligen
Protokollen unterstützt wird [3].
Glücklicherweise gibt es aber Konsortien und Organisationen, die sich sowohl mit verteilten, wie auch mit heterogenen Systemen auseinandersetzen
und in diesen Bereichen (offene) Standards entwickeln sowie teilweise frei
verfügbare Programmbibliotheken zur Verfügung stellen, die das Management solcher Systeme vereinfachen sollen. Verwendet oder erstellt man Komponenten, die auf einem offenen Standard basieren, erhöht sich natürlich die
Chance, diese Komponenten auch in anderen Projekten wieder einsetzen zu
können, oder gar auf Komponenten von Drittherstellern zurückgreifen zu
können, die ebenfalls diesem Standard genügen.
1.2
Ausblick
Im Zuge dieser Diplomarbeit sollen die Chancen und Problematiken von verteilten, heterogenen Applikationen erläutert und anhand einer Beispielimplementierung veranschaulicht werden. Besonderer Wert wird auf die Nutzung offener Standards und die mögliche Erweiterbarkeit der entwickelten
1
Internet Protocol. Ein weitverbreitetes Netzwerkprotokoll, das unter anderem die
Grundlage für das Internet ist.
2
http://www.bluetooth.com/
3
Es sei denn, das Bluetooth-Gerät unterstützt das Personal Area Networking Profile;
dann bettet es sich als IP-Komponente ein.
KAPITEL 1. EINLEITUNG
3
Applikation gelegt. Um die im Netzwerk verteilten Geräte und Dienste auszunutzen, wird eine grafische Benutzeroberfläche entwickelt, die es erlaubt,
verteilte Geräte zu koppeln. So sollen Geräte, die voneinander eigentlich
nichts wissen, zu einem Gesamtsystem verschmolzen werden, das für den
Benutzer einen Mehrwert im Vergleich zur Summe der Einzelkomponenten
darstellt.
Für die Beispielimplementierung werden die beiden offenen Standards
Universal Plug and Play 4 (UPnP) als Kommunikationsprotokoll und Open
Services Gateway Initiative 5 (OSGi) als erweiterbare Applikationsbasis zum
Einsatz kommen, auf deren Hintergrund in Kap. 2 bzw. 3 näher eingegangen
wird.
Das Kernthema dieser Arbeit, die Entwicklung einer Steuerinstanz zur
Kopplung verteilter Geräte, wird in den Kap. 4, 5 und 6 behandelt. In Ersterem soll erklärt werden, welche Anforderungen an die zu entwickelnde
Applikation gestellt werden, Zweiteres stellt vergleichbare Applikationen vor
und prüft diese auf Verwendbarkeit, Letzteres beschreibt schließlich die Umsetzung.
Kap. 7 zieht ein Resumee über die Beispielimplementierung und gibt
einen Ausblick auf mögliche zukünftige Entwicklungen.
1.3
Abgrenzung
Natürlich gibt es in dem in dieser Arbeit behandelten Themengebiet bereits
Projekte, die ähnliche oder ergänzende Ziele haben. Einige dieser Projekt
sollen im Folgenden kurz charakterisiert werden.
1.3.1
Unified Generic Control Point
Der Unified Generic Control Point [1] ist eine kombinierte Steuerinstanz
für UPnP- und Jini 6 -fähige Geräte, die es erlaubt, mit nur einer grafischen
Benutzeroberfläche, die Geräte dieser beiden Welten zu steuern. Sogar Ereignisse, die in UPnP oder Jini generiert werden, können auf Geräte des
jeweiligen anderen Protokolls weitergeleitet werden. Schließlich ist es noch
möglich über einen Ereignisdialog“ zu definieren, ob auf ein bestimmtes
”
Ereignis automatisch mit einer bestimmten Aktion reagiert werden soll. Das
ermöglicht bspw. das Szenario, dass beim Einschalten des Lichts A auch das
Licht B eingeschalten werden soll. Die Ereignisbehandlung ist jedoch nur für
eine Folgeaktion ausgelegt und bietet keine Möglichkeit auf den Wert des
Ereignisses zu reagieren – es ist nur bekannt, dass ein bestimmtes Ereignis
ausgelöst wurde [1].
4
http://www.upnp.org/
http://www.osgi.org/
6
http://www.jini.org/
5
KAPITEL 1. EINLEITUNG
1.3.2
4
Janus
Für die Entwicklung eines Automobil-Cockpit-Simulators wird eine OSGibasierte Applikation konzipiert und umgesetzt, die vor allem auf Multimodalität ausgelegt ist [7]. Das bedeutet, dass die Ein- und Ausgabegeräte des
Simulators mehrere Benutzerschnittstellen (z. B. Sprache, Text, Grafik) anbieten können. Durch Applikations-Plugins können diese Geräte miteinander
in Verbindung gesetzt werden, wobei je nach Situation eine geeignete Benutzerschnittstelle verwendet wird, um dem Benutzer die Interaktion mit dem
System zu ermöglichen. Die hier im Mittelpunkt stehende Multimodalität
wird im eigenen Prototyp jedoch nicht berücksichtigt [7].
1.3.3
Smart Home Server
Der Smart Home Server [39] setzt, wie auch das eigene Projekt, auf OSGi
und UPnP auf und stellt die Implementierung eines Servers für das intelli”
gente Eigenheim“ 7 dar. Im Gegensatz zu dem in dieser Arbeit vorgestellten
Ansatz werden die im Smart Home Server erkannten verteilten Geräte jedoch
als unabhängig voneinander gesehen. Dementsprechend ist es zwar möglich,
Emails abzurufen und die Jalousien der Wohnzimmerfenster fernzusteuern,
eine Kopplung dieser beiden Dienste zur Laufzeit ist jedoch nicht vorgesehen
und müsste bereits vorab definiert werden [39].
1.3.4
Shaman
Als zum eigenen Prototypen komplementäres Projekt soll Shaman [31], ein
erweiterbares Java-basiertes Dienst-Gateway, erwähnt werden: Es integriert
kleine netzwerkfähige Sensor-Aktuator-Module (SAM) in heterogene Netzwerke. Da SAMs typischerweise über sehr begrenzte Systemressourcen verfügen, werden gewisse Funktionalitäten, die für komplexe Service-Plattformen notwendig sind, vom leistungsstärkeren Gateway übernommen. Dadurch ist es möglich, SAMs über Technologien, wie z. B. Jini oder UPnP,
anzusprechen, die normalerweise zu aufwändig für sie wären. Um die Funktionalität von Shaman im eigenen Prototypen verwenden zu können, könnte
das Gateway-System als Plugin eingebunden werden [31].
1.3.5
Socam
Socam (Service-Oriented Context-Aware Middleware) [9] ist eine Middleware-Architektur, die auf einem Kontext-Modell, basierend auf der Web Ontology Language 8 (OWL), aufbaut und die Definition Kontext-spezifischer
Szenarien erlaubt. Über Sensorwerte wird versucht, den aktuellen Status und
7
Im Englischen werden für die Thematik des intelligenten, vernetzten, selbstregulierenden Eigenheims die Begriffe Home Automation“ und Smart Home“ verwendet.
”
”
8
http://www.w3.org/2004/OWL/
KAPITEL 1. EINLEITUNG
5
damit den Kontext festzustellen, in dem sich ein bestimmter Teil des Systems
befindet. Die Definitionen können mittels Vorwärts- und Rückwärtsverkettungen9 sowie einem hybriden Ansatz angegeben werden. Die Auswertung
der Definitionen erfolgt zur Laufzeit und resultiert in der Generierung von
Aktionen, die schließlich umgesetzt werden. Socam wurde als Sammlung von
OSGi-Bundles entwickelt [9].
1.3.6
Eigener Prototyp
Die eigene Implementierung setzt sich vor allem mit dem Prozess der Kopplung sowie der Umsetzung der definierten Kopplungen von verteilten Geräten auseinander. Der Unified Generic Control Point zeigt anhand von
UPnP und Jini, wie es möglich ist, zwei unterschiedliche Service-Plattformen
miteinander zu kombinieren. Der beschriebene Ansatz könnte als Vorlage
dazu dienen, um auch im eigenen Prototyp mehrere Protokolle unterstützen
zu können. Janus hat seinen Schwerpunkt auf der Multimodalität, die in
dieser Arbeit nicht behandelt wird. Die Idee der Kopplung der virtuellen
Ein- und Ausgabegeräte ist jedoch ähnlich zu dem, was in dieser Arbeit
erreicht werden soll. Im Gegensatz zum Smart Home Server soll es im eigenen Prototyp möglich sein, ein eingegangenes Email nach Schlüsselworten
zu durchsuchen, um anschließend die Steuerung der Jalousie entsprechend
vorzunehmen, wobei diese Definition zur Laufzeit erstellbar sein sollte. Shaman bietet sich als ideale Ergänzung an, um auch SAMs in die Kopplungsdomäne einbeziehen zu können und könnte nach einer Portierung in ein
OSGi-Bundle zum eigenen Prototyp hinzugefügt werden. Socam spezialisiert sich vor allem auf das Erkennen und Anwenden des aktuellen Kontexts,
in dem sich verschiedene Entitäten, die im System registriert sind, befinden.
Bewusstsein über den Kontext der entdeckten verteilten Geräte ist in dieser Arbeit nicht von Bedeutung, könnte jedoch als Erweiterung hinzugefügt
werden. Ebenso wäre der Ansatz der Vorwärts- und Rückwärtsverkettungen
eine gute Möglichkeit, um verschiedene Geräte automatisiert miteinander zu
verbinden.
Wichtig für diese Arbeit ist jedoch vordergründig, dass der beschriebene Prototyp dem Benutzer die Mittel zu Verfügung stellt, eine möglichst
große Zahl von Szenarien umzusetzen. Diese sollen dabei nach Möglichkeit
nicht vom Verwaltungs-System des Prototyps beschränkt werden, sondern
ausschließlich von den Möglichkeiten der zu koppelnden Geräte und der Fantasie des Benutzers.
9
engl. Forward- und Backward-Chaining
Kapitel 2
Verteilte Systeme
Die Grundlage für verteilte Systeme bilden Rechnernetze, die in [3] folgendermaßen charakterisiert werden:
Die Anzahl und Nutzung von Rechnernetzen nimmt explosionsartig zu. Vor zwei Jahrzehnten hatten nur wenige Leute Zugang
zu einem Netz. Heute ist die Computerkommunikation ein wesentlicher Bestandteil unserer Infrastruktur. Vernetzung wird in
jedem Bereich des Geschäftslebens genutzt, wie Werbung, Fertigung, Versand, Planung, Rechnungswesen und Buchhaltung.
Folglich haben die meisten Unternehmen mehrere Netze. Im Bildungswesen werden Rechnernetze von der Grundschule bis zur
Universität eingesetzt. Regierungsämter auf Bundes-, Landesund Kommunalebene arbeiten ebenso mit Rechnernetzen wie militärische Organisationen. Kurz: Rechnernetze sind überall.
Für gewöhnlich wird der Begriff Rechnernetze für mehrere miteinander verbundene autonome Computer verwendet. Der Unterschied zwischen Rechnernetzen und verteilten Systemen liegt darin, dass in einem verteilten System die Existenz mehrerer autonomer Rechner für den Benutzer nicht sichtbar ist [37]. Mit Benutzer“ ist hier nicht nur der Anwender eines Computer”
Programms gemeint, sondern auch schon dessen Programmierer. Damit ein
Rechnernetz abstrahiert und somit für den Programmierer unsichtbar“ ge”
macht werden kann, bedarf es einer Infrastruktur, die diese Abstraktion
vornimmt. Genau das ist die Aufgabe sogenannter Middleware 1 – sie bildet
eine Zwischenschicht zwischen dem Programm und dem Netzwerk [28].
Middleware erleichtert also den Zugriff auf entfernte Ressourcen, indem
sie den notwendigen Auf- und Abbau der Netzwerkverbindungen sowie die
direkte Netzwerkkommunikation übernimmt. Darauf aufbauend bieten Service-Plattformen weitere Möglichkeiten, wie das Auffinden und Nutzen von
verteilten Geräten2 über Hersteller-, Sprach- oder Plattformgrenzen hinweg.
1
2
Im Deutschen auch als Verteilungsplattform bezeichnet.
Als verteiltes Gerät wird ein Gerät bezeichnet, das Teil eines verteilten Systems ist.
6
KAPITEL 2. VERTEILTE SYSTEME
2.1
7
Middleware
In den letzten Jahren wurden mehrere Methoden entwickelt, die das Erstellen eines verteilten Systems basierend auf Middleware ermöglichen. Parallel
zur Entwicklung der Programmiersprachen passte sich auch Middleware dahingehend an, objektorientierte Programmiersprachen zu unterstützen [3].
Nicht-objektorientierte Middleware lässt sich unter dem Begriff Remote Procedure Call (RPC) zusammenfassen. Obwohl objektorientierte Programmiersprachen auf dem Vormarsch sind, gibt es immer noch Anwendungsfälle,
in denen RPC-Lösungen vorzuziehen sind, oder in denen eine Objektorientierung nicht viel Sinn macht. Zu diesen Fällen zählen vor allem InternetDienste, die meist eine Schnittstellenbeschreibung im Extensible Markup
Language3 (XML) Format besitzen. Auf diese besondere Gattung der RPCs
mittels XML-Beschreibung wird in Abs. 2.1.4 eingegangen. Ansonsten werden nur objektorientierte Lösungen beschrieben.
2.1.1
CORBA
CORBA, kurz für Common Object Request Broker Architecture, ist eine weitverbreitete objektorientierte Middleware, die von der Object Management
Group 4 (OMG) als offener Standard entworfen wurde. Wie alle anderen
Spezifikationen der OMG ist auch CORBA kostenlos von der Website der
OMG beziehbar5 . Die derzeit aktuelle Version der Spezifikation ist 3.0.3 vom
1. März 2004.
Um in einer Anwendung CORBA verwenden zu können, muss zunächst
definiert werden, auf welche Objekte entfernte Zugriffe durchgeführt werden sollen. Diese Objekte werden dann mit der Interface Definition Language 6 (IDL) als Schnittstellen definiert. Die somit erstellte IDL-Datei wird
in weiterer Folge kompiliert – der IDL-Compiler sollte bei jeder CORBADistribution dabei sein – und es werden einige Quelltext-Dateien in der
gewünschten Programmiersprache erzeugt, die schließlich im eigenen Programmcode verwendet werden können. Die Schlüsselkomponenten, die in
diesem Prozess generiert werden, sind die Stubs und die Skeletons. Die
Stubs abstrahieren die Kommunikation auf der Seite des Clients, während
die Skeletons die Kommunikation auf der Seite des Servers abstrahieren (s.
Abb. 2.1). Eine wichtige Eigenschaft von CORBA ist, dass die Kommunikation auch sprachübergreifend ausgeführt werden kann, da die IDL sprachunabhängig ist. Es ist also möglich, von einem Client-Programm, in C
geschrieben, auf einen Server, der in Java implementiert ist, zuzugreifen.
3
http://www.w3.org/XML/
http://www.omg.org/
5
Der genaue URL lautet: http://www.omg.org/technology/documents/corba spec
catalog.htm
6
http://www.omg.org/gettingstarted/omg idl.htm
4
KAPITEL 2. VERTEILTE SYSTEME
8
Abbildung 2.1: Funktionsweise von CORBA (nach [19]).
Es gibt mehrere Implementierungen der CORBA-Spezifikation für eine
Vielzahl von Sprachen – einige frei verfügbare sind:
• JavaTM IDL ist Teil des JavaTM 2 Platform Standard Edition Development Kit 7 (JDK) von Sun8 . Es genügt nach [35] der CORBAVersion 2.3.1 vom 7. Oktober 1999 und kann von beliebigen Javabasierten Programmen benutzt werden.
• MICO9 – das Wort ist eine rekursive Abkürzung10 nach dem Vorbild von GNU11 und bedeutet Mico is Corba“ – ist eine Open Source
”
Implementierung in C++. Im Juni 1999 wurde MICO, damals in der
Version 2.2.7, offiziell als konform gemäß der CORBA-Version 2.1 bezeichnet [38].
• mico/E12 ist eine frei verfügbare Implementierung nach dem Vorbild von MICO, jedoch in der Programmiersprache Eiffel. Das E“ im
”
Namen steht sowohl für Eiffel“ als auch für Education“ (dt. Ausbil”
”
dung) – eine Anspielung auf den ursprünglichen Grund für die Entwicklung: Es wurde für Kurse und Software-Übungen benötigt [16].
• Fnorb13 ist eine experimentelle CORBA Implementierung in Python,
die vom Centre of Excellence in Distributed Systems Technologies 14
(DSTC) geschaffen wurde und mittlerweile als Open Source 15 Projekt
bei SourceForge.net16 weiterentwickelt wird.
7
http://java.sun.com/j2se/
http://www.sun.com/
9
http://www.mico.org/
10
Eine rekursive Abkürzung beinhaltet sich selbst als Teil der Abkürzung. Siehe auch:
http://de.wikipedia.org/wiki/Rekursives Akronym
11
GNU steht für GNU is not Unix“
”
12
http://www.math.uni-goettingen.de/micoe/
13
http://fnorb.sourceforge.net/
14
http://www.dstc.edu.au/
15
Bei Open Source Projekten ist der Quellcode offen zugänglich und kann von jedermann
eingesehen werden.
16
Eine der größten Gemeinschaften für die Entwicklung freier Software. Die Adresse der
Website lautet http://www.sourceforge.net/.
8
KAPITEL 2. VERTEILTE SYSTEME
9
Neben den hier aufgelisteten Projekten gibt es noch eine Menge anderer,
auch kommerzieller, Implementierungen – eine umfangreiche Liste findet
sich in [2]. Jene Liste ist zwar nicht vollständig und beinhaltet auch einige
ungültige Links, doch sie gibt einen guten Überblick über die Menge an
CORBA-Implementierungen.
Damit ein Client über CORBA eine Methode auf einem Objekt des Servers ausführen kann, muss er zunächst eine Instanz dieses Objekts erhalten.
Eine Möglichkeit dafür ist, eine eigene Applikation, die einen Naming Service 17 beinhaltet zu starten, bei der sich zunächst die Server-Applikation
registriert, und die dann einem Client auf Anfrage das richtige Objekt über
eine Zeichenkette als Schlüssel vermittelt.
2.1.2
Java RMI
JavaTM Remote Method Invocation18 ist ebenso wie JavaTM IDL Teil des
JDK und kann somit in jeder Java-Applikation genutzt werden. Java RMI
kann auf zwei unterschiedliche Arten genutzt werden, die sich im Übertragungsprotokoll und damit der Anwendungsmöglichkeit unterscheiden:
1. Java RMI über Internet InterORB Protocol (IIOP) erlaubt es,
mit dem RMI API19 CORBA-kompatible Server- oder Client-Applikationen zu entwickeln.
2. Das Java Remote Method Protocol (JRMP) ist im Gegensatz
zu Java RMI über IIOP auf die Java-interne Verwendung ausgelegt
und dahingehend optimiert. Für Java-Versionen vor 5.0 mussten auch
für JRMP Stubs manuell erzeugt werden20 , seit der Version 5.0 ist
das nicht mehr notwendig – die benötigten Hilfsklassen werden zur
Laufzeit automatisch erstellt.
Beide Methoden unterstützen Distributed Garbage Collection 21 , jedoch
wird in [36] davon abgeraten, diese bei Java RMI über IIOP zu benutzen
und in [33] wird eingeräumt, dass es bei der Benutzung der Distributed Garbage Collection unter gewissen Umständen auch mit JRMP zu Problemen
kommen kann.
17
Der Naming Service ist eine Möglichkeit, Objekte mit Namen zu Verknüpfen. Eine
solche Verknüpfung heißt Name Binding [18]
18
Dt. der Methodenaufruf auf (netzwerktechnisch) entfernten Objekten.
19
Application Programming Interface – eine Auflistung und Beschreibung von Funktionen, die eine Software-Bibliothek zur Verfügung stellt. Im objektorientierten Sinn werden
nicht Funktionen sondern Objekte und deren Methoden beschrieben.
20
Vor Version 1.2 war auch das Erzeugen von Skeletons noch notwendig – seit 1.2 sorgte
ein zusätzliches Stub-Protokoll dafür, dass Skeletons nicht mehr verwendet werden mussten.
21
Garbage Collection (dt. automatische Speicherbereinigung) ist eine der herausragenden Eigenschaften von Java, die es Entwicklern ermöglicht, die Speicherverwaltung dem
System zu überlassen.
KAPITEL 2. VERTEILTE SYSTEME
10
Wie CORBA benötigt auch Java RMI eine RMI Remote Object Registry,
die – wie der Naming Service von CORBA – einem Client über einen Namen
ein Objekt vermittelt, das zuvor von einer Server-Applikation registriert
wurde.
2.1.3
.NET Remoting
.NET Remoting ist das Pendant zu Java RMI von Microsofts22 .NET Framework. Es ist sehr flexibel und kann, ähnlich wie Java RMI, mit zwei unterschiedlichen Protokollen verwendet werden: Die Daten werden entweder
binär, und damit schneller, oder im XML-Format zwischen den Endpunkten
transportiert. Die zweitere Methode ermöglicht die Interoperabilität mit anderen, von .NET Remoting unabhängigen, Kommunikationsprotokollen [17].
Wie bei CORBA und Java RMI muss auch bei .NET Remoting der
Server die extern erreichbaren Objekte zunächst im Remoting Framework
registrieren, bevor diese von Clients genutzt werden können.
Ein wichtiger Unterschied zwischen .NET Remoting und Java RMI liegt
in der Unterstützung von XML über HTTP (s. Abs. 2.1.4) bzw. CORBA.
CORBA-Implementierungen existieren zwar für viele Plattformen und Programmiersprachen, jedoch nicht für alle. XML über HTTP hingegen basiert
auf viel grundlegenderen Protokollen und kann daher leichter selbst implementiert werden. Außerdem werden Verbindungen über HTTP von nahezu
jeder verbreiteten Programmiersprache unterstützt. .NET Remoting entspricht damit dem derzeitigen Trend zur verstärkten Nutzung von Web Services (s. Abs. 2.1.4), die auf dem Austausch von XML-Nachrichten basieren.
Dabei soll aber nicht vergessen werden, dass es, neben anderen Programmiersprachen, auch für Java bereits Bibliotheken gibt, die die Benutzung
von Web Services sowohl auf der Server- wie auch auf der Client-Seite vereinfachen.
2.1.4
XML-RPC
XML-RPC steht für XML-basierte RPCs. Die verbreitetste Anwendungsform sind RPCs, die von HTTP23 -Anfragen getriggert werden. HTTP dient
dabei als Transportprotokoll, der Inhalt der Anfrage wird XML-kompatibel
formatiert. Auch für die XML-Nachrichten gibt es bereits einen weitverbreiteten Standard, das Simple Object Access Protocol (SOAP). Ein Beispiel soll
diese Zusammenhänge verdeutlichen. Um mit der Funktion activateHeating
per SOAP-kompatiblem XML-RPC die Heizung eines Gebäudes zu aktivieren, könnte folgende HTTP-Nachricht an den Server der Gebäudesteuerung
versandt werden:
22
http://www.microsoft.com/
Hypertext Transfer Protocol – Das Standardtransferprotokoll des Internets. Eine genauere Beschreibung findet sich in [37]
23
KAPITEL 2. VERTEILTE SYSTEME
11
Listing 2.1: Beispiel für eine SOAP-Anfrage
1
2
3
4
POST HTTP /1.0
Host: 10.17.1.24
Content - Type: text / xml
Content - length: 193
5
6
7
8
9
10
11
<? xml version = " 1.0 " ? >
< env:Envelope xmlns:env = " http: // www . w3 . org /2003/05/ soap envelope " >
< env:Body >
< activateHeating xmlns = " http: // sample . at / heating " / >
</ env:Body >
</ env:Envelope >
Die Zeilen 1 bis 4 beschreiben den HTTP-Header, Zeile 6 definiert den
Beginn der XML-Nachricht. Die Zeilen 7, 8, 10 und 11 sind Implementierungen des SOAP-Standards, die Zeile 9 beinhaltet schließlich den tatsächlichen
Aufruf der Funktion activateHeating, die keine Parameter benötigt. Die
XML-Nachricht wird vom Server verarbeitet und die entprechende Funktion ausgeführt. Anschließend wird noch eine Antwort generiert und an die
im HTTP-Header angegebene Adresse geschickt. Die Antwort kann entweder
Rückgabewerte der Funktion beinhalten oder kundtun, dass der Aufruf der
Funktion fehlgeschlagen ist. Die Fehlermeldung kann mit einer genaueren
Beschreibung des Problems versehen werden.
XML-RPC ist eine hervorragende Methode für die Kommunikation zwischen Anwendungen. Die dafür verfügbar gemachten Programmschnittstellen lassen sich als Web Services bezeichnen [41]. Das W3C24 hat einen Standard geschaffen, der Web Services genau spezifizieren lässt. Die Schnittstellen werden in der Web Services Description Language (WSDL), selbst
natürlich XML-konform, beschrieben und Entwicklern von Applikationen,
die diese Web Services nutzen wollen, zugänglich gemacht. Ein populäres
Beispiel für die Anwendung von Webservices ist die von Google25 zur Verfügung gestellten Schnittstellen, die es ermöglichen, von eigenen Applikationen
die umfangreichen Suchfunktionen von Google zu nutzen.
2.2
Service-Plattformen
Service-Plattformen bauen auf Middleware-Lösungen auf und bieten eine
weitere Vereinfachung für Entwickler und Benutzer von Service-Plattformbasierten Anwendungen. Die beiden wichtigsten Service-Plattformen sind
UPnP und Jini.
An dieser Stelle sollen nicht die genauen Funktionsweisen von UPnP und
Jini erläutert werden, da dies in [5] bzw. [42] bereits ausführlich gemacht
24
25
World Wide Web Consortium – siehe auch: http://www.w3.org/
Derzeit die Suchmaschine im Internet. Siehe auch http://www.google.com/
KAPITEL 2. VERTEILTE SYSTEME
12
wird. Stattdessen werden die wichtigsten Prinzipien von UPnP dargestellt,
die für das Verständnis der eigenen Implementierung, die in den Kap. 4, 5
und 6 folgt, notwendig sind.
UPnP definiert zwei grundlegende Typen von Komponenten: Das Gerät
(engl. Device) und die Steuerinstanz (engl. Control Point). Geräte beinhalten null oder mehrere Dienste (engl. Services), die wiederum null oder mehrere Aktionen (engl. Actions) und Statusvariablen (engl. State Variables)
beinhalten. Ein Gerät kann außerdem rekursiv null oder mehrere Sub-Geräte
mit jeweils wieder den selben Regeln beherbergen. Die genaue Spezifikation
eines Gerätes wird in einer XML-Datei beschrieben. Während Geräte und
Dienste lediglich eine Containerfunktion besitzen, liegt die wahre Funktionalität von UPnP-Geräten in den Aktionen und Statusvariablen. Aktionen
entsprechen Funktionen, die über XML-RPCs ausgeführt werden. Statusvariablen gehen den umgekehrten Weg und informieren von sich aus interessierte Netzwerkteilnehmer über Änderungen von Stati von Diensten. Das
Ausführen von Aktionen und Empfangen von Informationen der Statusvariablen obliegt den Steuerinstanzen. Es ist auch möglich, dass eine Netzwerkkomponente sowohl Gerät als auch Steuerinstanz ist.
Eine interessante Eigenschaft von UPnP ist weiters, dass es keiner Registrierungsstelle für Geräte bedarf, wie es etwa bei CORBA, Java RMI und
auch Jini notwendig ist. Stattdessen geben sich in ein Netzwerk eingebrachte
UPnP-Geräte mittels einer spezifizierten Nachricht selbstständig zu erkennen. Steuerinstanzen sind in der Lage diese Nachricht zu empfangen und
können aufgrund der XML-Beschreibungsdatei des Gerätes die Funktionalitäten des Gerätes auslesen und etwa in einer grafischen Benutzeroberfläche
präsentieren.
Kapitel 3
Heterogene Systeme
Um heterogene Systeme besser verstehen zu können, sei das Open Systems
Interconnection (OSI) Referenzmodell ins Gedächtnis gerufen. Es teilt die
Kommunikation in einem Rechnernetz in sieben Schichten auf, die jeweils
bestimmte Aufgaben erfüllen, wobei die Schicht j auf dem Rechner (auch
Host) k mit der Schicht j auf dem Rechner l kommuniziert. Innerhalb eines
Rechners kommuniziert die Schicht j über spezifizierte Schnittstellen mit
den angrenzenden Schichten j − 1 und j + 1 [3].
Abb. 3.1 zeigt die sieben Schichten des OSI-Referenzmodells. Die unterste Schicht definiert das Protokoll des physikalischen Mediums. Hier wird
bestimmt, ob als Übertragungsmedium elektrische Signale, Licht, Radiowellen o. ä. genutzt werden und wie digitale Signale auf diesem Übertragungskanal abgebildet werden. Die höherliegenden Schichten übernehmen dann
Aufgaben wie das Paketieren (Sicherungsschicht), das Vermitteln (Vermitt-
Abbildung 3.1: Das OSI-Referenzmodell (nach [37]).
13
KAPITEL 3. HETEROGENE SYSTEME
14
lungsschicht) oder das Transportieren (Transportschicht) der Daten [10].
Der Vorteil dieses Modells ist, dass eine Schicht ausgetauscht werden kann,
wenn sie die selben Schnittstellen nach oben und unten besitzt und die selbe
Funktionalität zur Verfügung stellt, ohne dass die anderen Schichten davon
erfahren müssen oder gar an die neue Situation angepasst werden müssten.
Damit die Kommunikation erfolgreich sein kann, muss die ersetzende Schicht
das selbe Protokoll sprechen, wie die entsprechende Schicht auf dem entfernten Rechner.
Die Austauschbarkeit der Schichten ist jedoch nicht nur äußerst komfortabel, sondern bringt auch Probleme mit sich, die auftauchen, wenn zwei
oder mehrere Netze miteinander verbunden werden sollen, die sich in einer
oder mehrerer Schichten unterscheiden. Den Zusammenschluss verschiedener
Netze nennt man Netzverbund oder Verbundnetz (engl. Internetwork) [37].
Zwischen den zusammengeschlossenen Netzen müssen Übersetzer“ geschal”
ten werden, die die notwendigen Konvertierungen zwischen den Protokollen vornehmen. Abhängig von der Schicht, auf der ein solcher Übersetzer
wirkt, heißt er z. B. Repeater (Schicht 1), Bridge (Schicht 2) oder Router (Schicht 3). Für höhere Schichten hat sich der Begriff Gateway eingebürgert [37], der im weiteren Verlauf auch für die Schichten 1 bis 3 verwendet wird. Gateways werden jedoch nicht nur verwendet, um inkompatible Netze miteinander, sondern auch um gleichartige Netze untereinander zu
einem größeren Netz zu verbinden. Die Gateways werden dann zu Verkehrsknotenpunkten, die je nach Typ entweder zur Optimierung der Datenübertragung beitragen können, oder empfangene Daten unbetrachtet zwischen
Netzen hin- und herkopieren [14].
Abb. 3.2 zeigt ein populäres Beispiel für ein Verbundnetzwerk: Ein Ether1
net -basiertes Local Area Network (LAN) und ein Wireless LAN 2 (WLAN)
werden über eine Wireless Bridge als Gateway miteinander verbunden. Daten, die auf der Ethernet-Seite eintreffen werden von der Bridge in WLANkompatible Pakete konvertiert und über eine Antenne ins drahtlosen Netzwerk eingebracht und umgekehrt. Ein Gerät auf der einen Seite kann mit
einem Gerät auf der anderen Seite kommunizieren, ohne wissen zu müssen,
dass eine Konvertierung vorgenommen wird. Lediglich die Schichten 1 und
2 sind von der Konvertierung betroffen.
3.1
Arten von Heterogenität
Verbundnetze können in der Ausprägung der Heterogenität sehr unterschiedlich sein. Manche Unterschiede sind einfacher zu überbrücken, andere schwieriger. Jedenfalls gibt es eine große Zahl an Merkmalen, in denen sich die
Teilnetze eines Netzverbundes unterscheiden können. Zur Verdeutlichung
1
2
Das weitverbreitetste Protokoll für verdrahtete LANs.
Der Überbegriff für drahtlose LANs.
KAPITEL 3. HETEROGENE SYSTEME
15
Abbildung 3.2: Ein Ethernet-LAN und ein WLAN werden über eine Wireless Bridge als Gateway zu einem Verbundnetz verknüpft. Das Gateway
nimmt die notwendigen Konvertierungen auf den Schichten 1 und 2 des OSIReferenzmodells vor und sorgt für eine transparente Verbindung zwischen
den beiden Netzen.
Tabelle 3.1: Auswahl an Merkmalen der Vermittlungschicht, durch die sich
Rechnernetze unterscheiden können (nach [37]).
Merkmal
Angebotener Dienst
Adressierung
Multicasting
Paketgröße
Dienstqualität
Fehlerbehandlung
Flusskontrolle
Sicherheit
Parameter
Abrechnung, Kostenerfassung
Mögliche Varianten
Verbindungsorientiert oder verbindungslos
Flach oder hierarchisch
Vorhanden oder nicht (auch Broadcasting)
Jedes Netz hat sein spezifisches Maximum
Vorhanden oder nicht; viele verschiedene Klassen und Arten
Zuverlässig, geordnet oder ungeordnet
Schiebefenster, Ratensteuerung, andere oder
keine
Datenschutzregeln, Verschlüsselung usw.
Verschiedene Timeouts, Flussspezifikationen
usw.
Nach Verbindungszeit, Paket, Byte oder keine
soll Tab. 3.1 dienen, die lediglich eine Auswahl möglicher Unterscheidungsmerkmale in der Vermittlungsschicht (Schicht 3) des OSI-Referenzmodells
darstellt.
Es gibt genügend Gründe, warum überhaupt unterschiedliche Netze miteinander verbunden werden müssen, und nicht nur ein Netzwerktyp verwendet wird. Ein einleuchtender Grundsatz besagt, dass es keine bestimmte
Netzwerktechnologie gibt, die sich für alle Bedürfnisse eignet [3]. Jede Technologie hat ihre spezifischen Eigenschaften, und der Einsatz leitet sich aus
den Bedürfnissen der jeweiligen Situation ab. Je ähnlicher die Eigenschaften
der Netze sind, desto einfacher ist die Realisierung des Verbundnetzes, da
die Konvertierungsarbeit und in weiterer Folge auch die Fehleranfälligkeit
der Gateways gering ist.
KAPITEL 3. HETEROGENE SYSTEME
16
Abbildung 3.3: Zwei Halb-Gateways verbinden zwei Netze über ein neutrales Protokoll miteinander.
Dass Verbundnetze aus heterogenen Teilnetzen nicht zu vermeiden sind
und in vielen Fällen die optimale Lösung bieten, ist einleuchtend. Auf die
Frage, welche Möglichkeiten es gibt, ein brauchbares Verbundnetz herzustellen, soll der folgende Abschnitt eingehen.
3.2
Methoden der Homogenisierung
Der Grundaufbau ist immer der selbe: Mehrere Netze werden über Gateways
miteinander verbunden, die den Datenaustausch über mehrere eventuell heterogene Netze ermöglichen. Ein Gateway kann dabei auch mehr als zwei
Netze miteinander verbinden und auf mehr als nur einer Schicht des OSIReferenzmodells wirken.
Ein Gateway kann wiederum, falls dies notwendig ist, in zwei HalbGateways geteilt werden. Ein Halb-Gateway übersetzt von einem Protokoll
in ein neutrales anderes Protokoll, von welchem ein weiteres Halb-Gateway
in ein drittes Protokoll übersetzt (s. Abb. 3.3). Ein Fall, wo das gewünscht
sein kann, ist, wenn zwei Netze von unterschiedlichen Firmen miteinander
verbunden werden sollen. In diesem Fall können sich die Firmen auf ein
neutrales Protokoll einigen, in das eingehende Daten konvertiert werden,
um von einem Halb-Gateway zum anderen transportiert zu werden [37].
Nach [37] ist für die interne Datenverarbeitung eines Verbundnetzes vor
allem der Aspekt ausschlaggebend, ob es verbindungsorientiert arbeitet oder
nicht, dementsprechend werden zwei Arten von Netzzusammenschlüssen definiert. In verbindungsorientierten Verbundnetzen wird für eine virtuelle Verbindung zwischen zwei Endpunkten eine Kette von Verbindungen aufgebaut,
die jeweils zwei Gateways miteinander verbinden. Die betroffenen Gateways
speichern die virtuellen Verbindungen in Tabellen ab und sorgen dafür, dass
Pakete einer virtuellen Verbindung immer den selben Pfad zurücklegen, und
dass die Reihenfolge der Pakete eingehalten wird.
Ein verbindungsloser Netzverbund hingegen gibt weder eine Garantie
über die Reihenfolge der Pakete noch über die Persistenz des internen Routings ab. Verschiedene Pakete, die von Host A zu Host B gelangen sollen,
können verschiedene Wege gehen. Das erlaubt es den Gateways Bandbreiten-
KAPITEL 3. HETEROGENE SYSTEME
17
Optimierung zu betreiben, da bei Überlastung einer Route auf eine andere
ausgewichen werden kann. Die möglicherweise dadurch erreichte Bandbreitenerhöhung ist jedoch nicht kostenlos, sondern hat den Nachteil, dass Pakete
einander überholen können und somit die Reihenfolge der Pakete nicht sichergestellt ist. Ist die Reihenfolge aber wichtig, so muss ein Protokoll einer
höheren Schicht die Reihenfolge wieder herstellen.
Abb. 3.4 illustriert diese beiden Arten von Verbundnetzen. Dabei ist zu
beachten, dass das verbindungsorientierte Verbundnetz nur dann funktionieren kann, wenn alle Teilnetze ebenfalls verbindungsorientierte Protokolle
zur Verfügung stellen. Bietet ein entstandenes Verbundnetz jedem Endpunkt
die Möglichkeit Pakete an jeden anderen Endpunkt zu schicken, spricht man
vom Vorhandensein eines Universaldienstes (engl. Universal Service). Ein
heterogenes Verbundnetz, das durch die Kombination von Hard- und Software einen Universaldienst anbietet nennt man auch Internet. Dem Benutzer
und den Anwendungsprogrammen wird die tatsächliche physische Netzstruktur komplett abstrahiert.
3.3
OSGi
OSGi definiert eine standardisierte, komponentenbasierte Umgebung für vernetzte Dienste [21]. Das spezifizierende Gremium ist die OSGi Alliance,
ein Zusammenschluss mehrerer Firmen und Organisationen, mit prominenten Mitgliedern wie BMW3 , Deutsche Telekom4 , IBM5 , Intel6 , Nokia7 , Siemens8 , Sun u. a. [24]. Die Kernkomponente, der für die Programmiersprache
Java konzipierten OSGi-Dienstplattform (Service Platform), ist das OSGiFramework.
Ursprünglich wurde es als Internet-Gateway für Anwendungen im Bereich der Home Automation entwickelt. Über ein OSGi-Framework kann einerseits den Anwendungen der Zugriff auf das Internet und andererseits die
Steuerung der Geräte des Haushalts von externen Standorten ermöglicht
werden. Zentraler Begriff ist der Dienst (engl. Service). Über auch nachträglich installierbare Software-Komponenten werden im Framework Dienste registriert, die von anderen Komponenten genutzt werden können. Zum
Beispiel könnte eine Anwendung, die Nachrichten an verschiedene Teilnehmer schickt, auf einen SMS9 -Dienst oder einen Email-Dienst zurückgreifen,
um Nachrichten an registrierte Teilnehmer zu schicken. Die Software, die den
3
http://www.bmw.com/
http://www.telekom3.de/
5
http://www.ibm.com/
6
http://www.intel.com/
7
http://www.nokia.com/
8
http://www.siemens.com/
9
Short Message Service – Standardprotokoll zum Versenden von Textnachrichten auf
Mobiltelefone.
4
KAPITEL 3. HETEROGENE SYSTEME
Abbildung 3.4: (a) zeigt einen Netzverbund mit virtuellen verketteten Verbindungen. Einzelne Pakete zwischen den Endpunkten A und B werden immer über den selben Pfad transportiert. Für die beiden Endpunkte erweckt
das Verbundnetz den Anschein einer persistenten Verbindung. (b) visualisiert einen verbindungslosen Netzverbund, in dem Datenpakete nach, für die
Endpunkte, nicht vorhersehbaren Kriterien verschiedene Wege zurücklegen
können. Pakete auf schnelleren Routen kommen daher eventuell früher an
als Pakete auf langsameren Routen – die Reihenfolge der Pakete kann sich
ändern.
18
KAPITEL 3. HETEROGENE SYSTEME
19
Abbildung 3.5: Ein OSGi-Framework aus Sicht der Verbundnetz-Thematik. Es ist ein zur Laufzeit erweiterbarer Container für Halb-Gateways,
die als neutrales Protokoll Java-Objekte verwenden. In diesem Fall wird einer Benachrichtigungs-Software das Versenden von Nachrichten über SMS
oder Email ermöglicht. Die tatsächliche Kommunikation mit einem SMSoder Email-Server wird vom jeweiligen Bundle abstrahiert.
SMS-Dienst registriert, könnte von einem Mobilfunkbetreiber zur Verfügung
gestellt werden. Man könnte ein OSGi-Framework somit auch als Container
für Halb-Gateways sehen, deren neutrales Protokoll die Programmiersprache
Java ist (s. Abb. 3.5).
Das OSGi-Framework als Internet-Gateway war zwar das Ziel der ersten
Version der OSGi-Spezifikation [20], im Laufe der letzen Jahre hat es sich
allerdings auch für andere Bereiche als einsetzbar erwiesen [21]. Seit der
ersten Version (Mai 2000) wurde die Spezifikation erweitert, um vor allem
den Anforderungen der Automobilbranche und mobiler Geräte gerecht zu
werden, für die eigene Expertengruppen (engl. Expert Groups) eingerichtet
wurden: die Vehicle Expert Group 10 und die Mobile Expert Group 11 .
Die aktuelle Version ist die vierte und wurde im Oktober 2005 verabschiedet. Sie heißt OSGi Service Platform, Release 4 CORE“ und teilt sich
”
in zwei Teile:
• CORE, veröffentlich in [22], beschreibt das Framework selbst und
spezifiziert die Kernkomponenten.
• COMPENDIUM beinhaltet die Spezifikationen nützlicher Dienste
wie Protokollierung, Benutzeradministration und XML-Verarbeitung
und wurde in [23] herausgegeben.
3.3.1
Das OSGi-Framework
Ein OSGi-Framework ist eine Laufzeitumgebung für erweiterbare, herunterladbare Applikationen auf Basis der Java Laufzeitumgebung. Eine in einem
10
11
http://osgi.org/about/charter veg.asp?section=1
http://osgi.org/about/charter meg.asp?section=1
KAPITEL 3. HETEROGENE SYSTEME
20
OSGi-Framework installierte Anwendung heißt Bundle und ist ein Java Archive (JAR)12 mit erweitertem JAR-Manifest (s. Abs. 3.3.2). Der Clou dabei
ist, dass eigenständige Applikationen im OSGi-Framework unabhängig voneinander laufen, aber bei Bedarf direkt über Objekt-Instanzen miteinander
kommunizieren können. Es muss somit nur eine Java Virtual Machine 13
(JVM) gestartet werden, um mehrere Java-Applikationen laufen zu lassen,
und die Kommunikation zwischen den Applikationen kann direkt erfolgen,
ohne den Umweg über Protokolle wie CORBA oder RMI gehen zu müssen.
OSGi macht sich dabei vor allem zwei Eigenschaften von Java zu Nutze:
Das dynamische Laden von ausführbarem Code zur Laufzeit und das Konzept der multiplen Class Loader. Erstere erlaubt das Installieren von Bundles
auch zur Laufzeit des Frameworks. Zweitere ermöglicht es, dass jedes Bundle
seine Klassen mit einem eigenen Class Loader lädt, was dazu führt, dass
die einzelnen Bundles komplett voneinander abgeschottet arbeiten können.
Jedes Bundle kann jedoch Instanzen beliebiger Klassen im Framework registrieren, auf die dann auch von anderen Bundles direkt zugegriffen werden
kann.
Zur Laufzeit des Frameworks können Bundles installiert, deinstalliert,
aktualisiert (z. B. zum Laden einer neuen Version), aufgefrischt (Löschen
der temporär angelegten Dateien), gestartet und gestoppt werden – diese
Eigenschaft entspricht dem Component Configurator Pattern, das in [30]
beschrieben wird. Dadurch eignet sich OSGi hervorragend für Applikationen,
die Plugins (in Form von Bundles) unterstützen wollen. Die Plugins werden
als JAR-Dateien installiert und sind sofort verfügbar – die OSGi-basierte
Applikation muss nicht neu gestartet werden. Ist eine neue Version eines
Plugins erhältlich, kann diese jederzeit, auch zur Laufzeit der Applikation,
die alte ersetzen oder parallel zur alten Version installiert werden.
3.3.2
Das OSGi-Bundle
Ein Bundle ist eine als JAR-Datei vertriebene Applikation oder SoftwareBibliothek. Damit ein OSGi-Framework weiß, wie es mit einem Bundle umzugehen hat, sind einige Meta-Angaben in der Manifest-Datei14 des JARs
notwendig. Die wichtigsten auf diese Art einstellbaren Eigenschaften sollen
kurz erläutert werden. Eine vollständige Liste befindet sich in [22]:
Bundle-Activator definiert den Einstiegspunkt für das Bundle, wenn es
sich um eine Applikation handelt. Ist das Bundle eine Bibliothek,
muss dieser Eintrag nicht angegeben werden. Die angegebene Klasse
12
Ein JAR ist ein ZIP-basiertes komprimiertes oder unkomprimiertes Archiv, kann kompilierte Klassen und Ressourcen beinhalten und eine eigenständige Applikation oder eine
Software-Bibliothek darstellen.
13
Eine Instanz einer Java Laufzeitumgebung
14
Das Manifest ist die Datei MANIFEST.MF im Verzeichnis META-INF der JAR-Datei.
KAPITEL 3. HETEROGENE SYSTEME
21
muss das Interface org.osgi.framework.BundleActivator implementieren, wo die Methode start definiert wird, die der main Methode in
gewöhnlichen Applikationen entspricht.
Beispiel: Bundle-Activator: net.bebedizo.foo.Activator
Export-Package gibt an, welche Java-Packages für andere Bundles sichtbar sein sollen. Alle nicht hier angeführten Packages und die darin enthaltenen Klassen sind für andere Bundles unsichtbar. Jedes Package
kann (und soll) seine eigene Versionsnummer haben, die unabhängig
von der Version des Bundles ist. Einzelne Packages werden durch Beistriche getrennt.
Beispiel: Export-Package: net.bebedizo.foo;version=2.3.1,net
.bebedizo.bar;version=0.3.2
Import-Package ist die Möglichkeit eines Bundles zu definieren, welche
Packages, die von anderen Bundles exportiert wurden, für die Funktionalität dieses Bundles notwendig sind.
Beispiel: Import-Package: net.bebedizo.foo;version=2.3.1,net
.bebedizo.bar
Das vollständige Manifest des lauffähigen Bundles Example-Bundle“,
”
das ein Package importiert, eines exportiert und von zwei anderen Bundles
explizit abhängt, sieht folgendermaßen aus:
Manifest-Version : 1.0
Bundle-ManifestVersion : 2
Bundle-Name : Example-Bundle
Bundle-SymbolicName : net . bebedizo . osgi . example
Bundle-Version : 1.3.12
Bundle-Activator : net . bebedizo . osgi . example . Activator
Bundle-Vendor : Bernhard Wally
Import-Package : org . osgi . framework ; version =1.3.0
Require-Bundle : org . eclipse . osgi . services , org . eclipse .
osgi
Export-Package : net . bebedizo . osgi . example . share ; version
=1.1.0
3.3.3
Dienste
Wie eingangs erwähnt, dreht sich bei OSGi alles um Dienste. Ein Dienst ist
nichts anderes als ein Java-Objekt, das im Framework registriert wird. Für
gewöhnlich wird man zunächst ein Interface, das die Methoden des Dienstes
beschreibt, definieren und anschließend eine Implementierung des Interfaces im Framework registrieren. Die folgenden Code-Fragmente beschreiben
die Schritte, die notwendig sind, um einen Dienst zu definieren, danach im
Framework zu registrieren und schließlich zu nutzen.
KAPITEL 3. HETEROGENE SYSTEME
22
Zunächst wird ein Interface (s. Lst. 3.1) und seine Implementierung (s.
Lst. 3.2) definiert. In diesem Fall ein Service, das nur eine Methode beinhaltet, die Hello“ auf die Konsole ausgibt.
”
Listing 3.1: Das HelloService Interface.
package net . bebedizo . foo ;
public interface HelloService
{
public void sayHello () ;
}
Listing 3.2: Die HelloService Implementierung.
package net . bebedizo . foo ;
public class HelloServiceImpl implements HelloService
{
public void sayHello ()
{
System . out . println ( " Hello " ) ;
}
}
Um nun ein HelloServiceImpl-Objekt im OSGi-Framework zu registrieren, dient die Methode registerService, die im für Bundles zentralen Interface org.osgi.framework.BundleContext definiert wird. Ein Objekt vom
Typ BundleContext wird jedem Bundle bei dessen Start zur Verfügung gestellt. Der Rückgabewert der Methode registerService ist ein Objekt vom
Typ org.osgi.framework.ServiceRegistration, das später zum Austragen
des Dienstes aus dem OSGi-Framework verwendet werden kann (s. Lst. 3.3).
Listing 3.3: Registrierung des HelloService im OSGi-Framework beim
Start des Bundles.
package net . bebedizo . foo ;
// ...
private ServiceRegistration registration ;
public void start ( BundleContext bundleContext )
throws Exception
{
registration = bundleContext
. registerService ( HelloService . class . getName () ,
new HelloServiceImpl () , null ) ;
}
// ...
KAPITEL 3. HETEROGENE SYSTEME
23
Ab diesem Zeitpunk steht das HelloService anderen Bundles zur Verfügung. Um die Registrierung zu einem späteren Zeitpunkt (z. B. wenn das
Bundle gestoppt wird) wieder zu annullieren, kann die Methode unregister
des ServiceRegistration-Objekts aufgerufen werden (s. Lst. 3.4).
Listing 3.4: Austragen des HelloService aus dem OSGi-Framework.
package net . bebedizo . foo ;
// ...
public void stop ( BundleContext bundleContext )
throws Exception
{
registration . unregister () ;
}
// ...
Wie in Lst. 3.3 ersichtlich, wird der Dienst unter dem Namen InterfaceKlasse, HelloService, registriert. Um diesen Dienst, also genauer gesagt das
HelloServiceImpl-Objekt, das registriert wurde, von einem anderen Bundle
aus nutzen zu können, muss es vom OSGi-Framework angefordert werden.
Die notwendigen Schritte werden in Lst. 3.5 dargestellt.
Listing 3.5: Nutzen des registrierten HelloService von einem anderen
Bundle aus.
package net . bebedizo . bar ;
import net . bebedizo . foo . HelloService ;
// ...
public void start ( BundleContext bundleContext )
throws Exception
{
HelloService helloService = bundleContext . getService (
bundleContext . getServiceReference ( HelloService
. class . getName () ) ) ;
helloService . sayHello () ;
}
// ...
Die Methoden registerService und getService sind also für den Austausch von Objekten zwischen verschiedenen Bundles zuständig. Mit diesem
Mechanismus kann ein Bundle Schnittstellen definieren, die in einem Interface gesammelt werden. Andere Bundles beantragen vom OSGi-Framework
eine Instanz vom Typ des Interfaces und können die darin definierten Methoden nutzen.
KAPITEL 3. HETEROGENE SYSTEME
3.3.4
24
OSGi-Implementierungen
Die OSGi-Spezifikation definiert lediglich eine Sammlung an Interfaces –
lauffähige Versionen müssen daher selbst implementiert werden. Glücklicherweise kann mittlerweile aus einer Menge an Implementierungen gewählt
werden – es gibt sowohl kommerzielle, als auch frei verfügbare. Zu den kommerziellen Produkten, die teilweise auch von der OSGi Alliance zertifiziert
wurden, gehören jene von Atinav Inc.15 , Connected Systems16 , Gatespace
Telematics AB17 , IBM und ProSyst Software18 [25]. Die drei wichtigsten frei
verfügbaren Implementierungen sind: Knopflerfish 19 , Equinox 20 und Felix 21
(ehemals Oscar OSGi22 ).
Felix ist eine eigenständige Implementierung ohne Verbindungen zu anderen Projekten, Knopflerfish stellt große Teile der Code-Basis für Ubiserv23 , das kommerzielle OSGi-Framework von Gatespace Telematics AB
und Equinox bildet die Grundlage für die Java-Entwicklungsumgebung
Eclipse24 und wurde von der OSGi-Alliance als Referenz-Implementierung
der aktuellen Version, Release 4, definiert [6].
15
http://www.atinav.com/
http://www.connectedsys.com/
17
http://www.gatespacetelematics.com/
18
http://www.prosyst.com/
19
http://www.knopflerfish.org/
20
http://www.eclipse.org/equinox/
21
http://incubator.apache.org/felix/
22
http://oscar.objectweb.org/
23
http://www.gatespacetelematics.com/products/ubiserv osgi.shtml
24
http://www.eclipse.org/
16
Kapitel 4
Anforderungen
Die Anforderungen an den zu entwickelnden Prototyp werden zunächst grob
definiert und anschließend nach den Regeln der Model-View-Control (MVC)
Architektur verfeinert. MVC ist ein Programmier-Entwurfsmuster, bei dem
die Darstellung (View), die Steuerung (Control) und die darzustellenden
Daten selbst (Model) als drei verschiedene Komponenten gesehen werden,
was die Modularisierung des Programm-Codes erleichtert [8]. Durch genau
spezifizierten Schnittstellen zwischen diesen drei Komponenten ist es auch
möglich, jede der Komponenten durch eine entsprechend passende andere zu
ersetzen. Das erlaubt z. B. das Definieren verschiedener Darstellungsformen
für ein und dasselbe Datenmodell.
Der Prototyp soll eine Applikation mit grafischer Benutzeroberfläche
(engl. Graphical User Interface, kurz GUI) sein, die es ermöglicht, ursprünglich unabhängige, verteilte Geräte miteinander in Bezug zu setzen. Verteilte Geräte bieten Schnittstellen an, über die gewisse Funktionalitäten des
Gerätes genutzt werden können. Zum Beispiel kann ein Gerät, das den Zugriff auf ein Email-Postfach ermöglicht, Funktionen zum Lesen empfangener
oder zum Versenden erstellter Emails anbieten. Ein anderes Gerät könnte
einen Bewegungsmelder beinhalten und darüber informieren, wenn Bewegung detektiert würde. Diese beiden Geräte könnten zu einer Anwendung
verschmolzen werden, in der Benachrichtigungs-Emails versandt werden, sobald eine Bewegung registriert wird.
Das GUI soll die Geräte als Blöcke darstellen und dem Benutzer die
Möglichkeit geben, eine Beziehung herzustellen, indem eine gerichtete Verbindungslinie gezeichnet wird (s. Abb. 4.1). Dieses Verhalten lässt sich leicht
in eine MVC-Architektur abbilden: Die Geräte und die Verbindung bilden
das Model, sie sind die Akteure, die gesteuert und dargestellt werden sollen.
Die View ist das GUI, das die Daten repräsentiert und z. B. durch Mausinteraktion die Definition der Verbindungen ermöglicht. Sie leitet den Wunsch
des Benutzers, der die Verbindung definiert hat, an die Control weiter, die
für den tatsächlichen Verbindungsaufbau zwischen den Geräten sorgt.
25
KAPITEL 4. ANFORDERUNGEN
26
Abbildung 4.1: Die beiden Geräte werden durch die gerichtete Verbindungslinie miteinander in Bezug gesetzt. Das Verwaltungs-Programm, das
diese Verbindung ermöglicht hat, muss sie in weiterer Folge umsetzen. Sobald Bewegung registriert wird, soll ein Email mit dem Text Einbruch?“
”
erstellt und versandt werden.
Abbildung 4.2: Die Funktion, die die Schnittstelle Email versenden“
”
repräsentiert, benötigt zwei Eingangsparameter (links): die EmpfängerEmail-Adresse und die zu versendende Nachricht. Als Ausgangsparameter
(rechts) wird ein boolscher Wert zurückgegeben: War der Versand erfolgreich?
4.1
Model
Abb. 4.1 lässt jedoch noch einige Fragen offen, denn an wen wird das Email
gesandt? Und wird, wenn der Bewegungsmelder zehn mal pro Sekunde eine
Bewegung registriert, jedesmal ein Email generiert? Um diese Fragen zu beantworten, müssen zunächst die Schnittstellen der Geräte genauer definiert
werden.
4.1.1
Komponenten
Der Zugriff auf verteilte Geräte funktioniert über entfernte Funktions- oder
Methodenaufrufe, wie in Abs. 2.1 erläutert. Jede Schnittstelle eines verteilten Gerätes kann somit als Funktionsaufruf betrachtet werden, der eine gewisse Anzahl an Eingangsparametern benötigt und als Ergebnis bestimmte
Ausgangsparameter liefert (s. Abb. 4.2). Die Zahl der Parameter kann dabei
auch null betragen.
Anders ausgedrückt definiert dieser Funktionsblock drei Ports: Zwei Eingangs-Ports (engl. Input Ports), die Daten (in Form von Zeichenketten) annehmen und einen Ausgangs-Port (engl. Output Port), der Daten (boolsche
Werte) zur Verfügung stellt. Nachdem sie mit Daten operieren, werden sie
als Daten-Input-Ports (DIPs) und Daten-Output-Port (DOP) bezeichnet.
Wird der Wert eines Eingangsparameters gesetzt, so kann gleichbedeutend
gesagt werden: Dem DIP wird ein Wert zugewiesen“. Die Situation des
”
Ausgangsparameters wird als der DOP stellt einen Wert zur Verfügung“
”
bezeichnet.
KAPITEL 4. ANFORDERUNGEN
27
Abbildung 4.3: Diese Komponente bietet die Möglichkeit den Zeitpunkt des
Funktionsaufrufes genau zu bestimmen: Wenn der rechteckig gekennzeichnete Funktionsaufruf-Port aktiviert wird. Daten-Ports werden zur besseren
Unterscheidung weiterhin als Dreiecke dargestellt.
Dieses Konstrukt – der Funktionsblock mit mehreren Ein- und Ausgangsparametern – wird in weiterer Folge als Komponente bezeichnet. Wird
die von einer Komponente repräsentierte Funktionalität (in diesem Beispiel
das Versenden des Emails) ausgeführt, so wird das Aktivierung der Komponente genannt.
Nun stellt sich die Frage, wann die Sende-Funktion eigentlich aufgerufen
wird. Der Aufruf könnte erfolgen, sobald einer der beiden Eingangsparameter definiert wurde, oder nur dann, wenn der Nachrichten-Parameter eine
neue Zeichenkette erhalten hat. Beide Möglichkeiten sind aber nicht besonders flexibel, es muss daher eine andere Möglichkeit gefunden werden. Eine
einfache Lösung ist es, den Zeitpunkt der Ausführung durch einen dritten
Input-Port zu steuern. Dieser kann keine Daten annehmen, sondern wird aktiviert. Durch ihn können den DIPs beliebig oft Werte zugewiesen werden;
die Funktion wird erst ausgeführt, sobald dieser spezielle Port aktiviert wird
(s. Abb. 4.3).
Es ist nun theoretisch möglich die Input-Ports der Komponente zu setzen oder zu aktivieren, doch woher kommen die Daten bzw. der Auslöser für
den Funktionsaufruf? Der Benutzer könnte die Daten für die DIPs per Tastatur eingeben und mit einem Mausklick das Aktivieren einer Komponente
verlangen. Diese Methode ist zwar praktisch, und dem Benutzer sollte auf
jeden Fall die Möglichkeit gegeben werden manuell einzugreifen, jedoch wird
auf diese Weise das Szenario mit dem Bewegungsmelder nicht verwirklicht
werden können, da in diesem ein gewisser Automatismus verlangt wird.
Das Aktivieren von Komponenten sollte vielmehr von anderen Komponenten aus ermöglicht werden. Schaltet man mehrere Komponenten hintereinander ergibt sich ein Programmfluss, der den sequentiellen Aufruf mehrerer Funktionen darstellt. Die Funktionsaufruf-Input-Ports werden deswegen
auch Programmfluss-Input-Ports (PIP) genannt. Damit eine Komponente,
die nach einer anderen geschaltet ist auch wirklich erst nach der vorhergehenden aktiviert wird, ist es sinnvoll, wenn jede Komponente neben dem
PIP auch einen Programmfluss-Output-Port (POP) definiert (s. Abb. 4.4),
um anzuzeigen, dass eine Funktion ausgeführt wurde.
Doch nicht nur die PIPs sollten von anderen Komponenten aus (über deren POPs) aktiviert werden können. Auch die DIPs sollten Werte von DOPs
KAPITEL 4. ANFORDERUNGEN
28
Abbildung 4.4: (a) Eine flexibel einsetzbare Komponente mit drei InputPorts (links) und zwei Output-Ports (rechts). Der mit Funktionsaufruf“ ge”
kennzeichnete Port stellt den PIP dar, der mit Funktion ausgeführt“ be”
zeichnete Port ist der POP. (b) zeigt die innere Funktionsweise dieser Komponente: Von außen nicht ersichtlich, wird zunächst aus Empfängeradresse
und Nachricht ein Email erstellt, dann eine Netzwerkverbindung zu einem
Email-Server aufgebaut und das Email verschickt. Die Antwort des Servers
wird in einen boolschen Wert umgewandelt und an den DOP weitergeleitet.
anderer Komponenten zugewiesen bekommen können, um Ausgangsparameter einer Funktion als Eingangsparameter einer anderen nutzen zu können.
Zur Verdeutlichung soll Abb. 4.5 dienen, die zwei Komponenten über deren Ports miteinander koppelt. Kopplungen werden in Abs. 4.1.2 genauer
spezifiziert.
Eine Komponente durchläuft zusammenfassend folgende Stadien: Zunächst ist sie ein Funktionsblock mit Wert-losen DIPs, die im nächsten
Schritt Werte zugewiesen bekommen. Danach kann die Komponente über
den PIP aktiviert werden (manuell durch den Benutzer oder durch eine vorgeschaltete Komponente), was das Ausführen der dahinterliegenden Funktion, mit den aktuellen Werten der DIPs, bedeutet. Ist die Funktion ausgeführt, stellen die DOPs die Rückgabewerte der Funktion zur Verfügung
und danach wird der POP aktiviert, um zu signalisieren, dass die Funktion
ausgeführt wurde.
Man kann eine Komponente als Blackbox mit einer Menge an Input- und
Output-Ports sehen, mit der ausschließlich über die Ports interagiert wird.
Sie kann intern beliebig aussehen und entfernte Funktionsaufrufe ebenso
durchführen wie simple Funktionen (etwa eine Addition).
KAPITEL 4. ANFORDERUNGEN
29
Abbildung 4.5: (a) zeigt eine neue Komponente, deren Funktionalität das
Protokollieren von Daten ist (z. B. in eine Log-Datei). (b) stellt die Kopplung der Email-Komponente mit dieser dar. Der Ausgangsparameter der
Email-Funktion wird als Eingangsparameter für die Protokollier-Funktion
verwendet. Ist die Email-Funktion beendet und der Parameter über die
Daten-Kopplung übertragen, wird die Protokollier-Komponente über die
Programmfluss-Kopplung aktiviert.
Erweiterte Komponenten
Die oben vorgestellte Protokollier-Komponente ist ein relativ simpler Fall:
Sie repräsentiert eine isolierte Funktion. Isoliert bedeutet in diesem Zusammhang, dass die Funktion an keinen Kontext gebunden ist, wie dies etwa bei
Methoden von Objekten der Fall ist. Methoden stehen immer im Kontext
des Objekt zu dem sie gehören. Die Protokollier-Funktion kann einfach aufgerufen werden, ohne Genaueres wissen zu müssen, schließlich wird der übergebene Wert einfach in eine Log-Datei geschrieben. Bei Kontext-behafteten
Funktionen kann es angebracht sein, Funktionen des gleichen Kontextes in
einer einzigen Komponente zu repräsentieren.
Als Beispiel soll ein Array-Objekt (s. Lst. 4.1) dienen, mit dem über drei
Methoden kommuniziert werden kann:
• eine zum Definieren der Elemente,
• eine zum Auslesen eines bestimmten Elements und
• eine zum Abfragen der Größe des Arrays.
Es ist grundsätzlich kein Problem diese drei Methoden als drei unterschiedliche Komponenten darzustellen (s. Abb. 4.6) und isoliert zu verwenden.
Kompliziert wird es jedoch, wenn mehrere Array-Instanzen unterstützt
werden sollen – die drei Methoden müssen jeweils einer Instanz des ArrayObjekts zugewiesen werden. Diese Semantik könnte durch eine zusammengesetzte Komponente realisiert werden, die mehrere Funktionen (oder in
diesem Fall Methoden) vereint. Abb. 4.7 stellt eine solche Komponente dar.
KAPITEL 4. ANFORDERUNGEN
Listing 4.1: Die Array-Klasse in Java-Syntax.
public class Array
{
private Object [] elements ;
/*
* Entspricht " Array setzen ".
*/
public void setArray ( Object [] elements )
{
this . elements = elements ;
}
/*
* Entspricht " Größe abfragen ".
*/
public int getSize ()
{
return elements . length ;
}
/*
* Entspricht " Element auslesen ".
*/
public Object getElement ( int index )
{
return elements [ index ];
}
}
Abbildung 4.6: Die drei Methoden des Array-Objekts als isolierte Komponenten.
30
KAPITEL 4. ANFORDERUNGEN
31
Abbildung 4.7: Die drei Methoden des Array-Objekts in einer zusammengesetzten Komponente.
Abbildung 4.8: Eine if-Anweisung als Komponente dargestellt. Wird der
PIP ( Wenn“) aktiviert, so wird geprüft, ob der Zu prüfende Wert“ WAHR
”
”
oder FALSCH ist. Ist er WAHR, so wird der obere POP ( Dann“), ansonsten der
”
untere ( Sonst“) aktiviert. Ob gekoppelte Komponenten aktiviert werden,
”
hängt davon ab, mit welchem POP sie verbunden sind. Auf ähnliche Weise
lassen sich auch weitere Sprachelemente wie Schleifen (s. Abb. 4.15) und
switch-Anweisungen in Komponenten überführen.
Sie definiert für jede Methode ein PIP-POP-Paar und entsprechende DIPs
und DOPs. Würde nun der Setzen des Arrays“-PIP aktiviert werden, so
”
würde die Komponente nur die Methode zum Setzen des Arrays ausführen
und dazu den Wert des Array“-DIP als Eingangsparameter verwenden. Da”
nach würde die Komponente den Array gesetzt“-POP aktivieren.
”
Eine zusammengesetzte Komponente hat den Vorteil, dass sie dem Benutzer den Zusammenhang mehrerer Funktionen verdeutlichen kann. Der
Nachteil ist, dass zusammengesetzte Komponenten etwas unübersichtlicher
sind und eine genaue Definition der Ports voraussetzen, um dem Benutzer
vermitteln können, welche Ports zu welcher Sub-Funktion der Komponente
gehören.
Zur Steuerung des Programmflusses steht in den meisten Programmiersprachen eine if-Anweisung zur Verfügung, bei der der Programmfluss in
eine von zwei möglichen Richtungen weitergeleitet wird. Auch solche Sprachelemente können als Komponente dargestellt werden, wie Abb. 4.8 zeigt.
Ereignisse
Die bisher betrachteten Komponenten beruhen alle auf dem selben Schema:
Eine Komponente wird aktiviert, führt ihre Funktionalität unter Berücksichtigung der Eingangsparameter aus, stellt gegebenenfalls Ausgangsparameter
zur Verfügung und aktiviert einen POP, um gekoppelte Komponenten zu ak-
KAPITEL 4. ANFORDERUNGEN
32
Abbildung 4.9: Ein Ereignis als Komponente. Wird vom Bewegungsmelder eine Bewegung detektiert, so informiert er seine registrierten Beobachter
(darunter diese Komponente) darüber. Die Komponente aktiviert daraufhin
ihren POP und bildet damit die Quelle für einen neuen Programmfluss.
Abbildung 4.10: Ein Ereignis, das von einem dimmbaren Licht ausgesandt
wird. Diese Komponente stellt zusätzlich zum POP noch einen DOP mit dem
aktuellen Dimm-Wert zur Verfügung.
tivieren. Diese Art von Komponenten kann das eingangs erwähnte Beispiel
von der Bewegungsmelder-Email-Applikation nicht umsetzen. Denn darin
wird verlangt, dass der Bewegungsmelder von sich aus meldet, wenn eine
Bewegung erkannt wird.
Allgemein wird so ein Verhalten durch das Beobachter-Entwurfsmuster
modelliert, das besagt, dass ein Subjekt (in diesem Fall das verteilte Gerät
mit dem Bewegungsmelder) sogenannten Beobachtern (engl. Listeners) die
Möglichkeit bietet bei sich registriert zu werden. Tritt eine Statusänderung
im Subjekt auf, so werden alle registrierten Beobachter darüber informiert
[8]. Den Beobachtern wird ein Ereignis (engl. Event) übermittelt.
Um dieses Entwurfsmuster umsetzen zu können, müssen verteilte Geräte,
wie jenes mit dem Bewegungsmelder, die Registrierung von Beobachtern
unterstützen. Ist dies nicht der Fall, muss der Umweg über regelmäßiges
Abfragen des Zustands (engl. Polling) genommen werden, sofern das Gerät
eine Schnittstelle bietet, die das Auslesen des aktuellen Status ermöglicht.
Ein Ereignis tritt, vom Standpunkt des Beobachters gesehen, spontan
auf – er wird zu einem beliebigen Zeitpunkt vom Subjekt informiert. Um
ein Ereignis als Komponente zu modellieren, muss sich eine solche Komponente als Beobachter beim entsprechenden Subjekt registrieren. Nachdem
ein Ereignis vom Beobachter nicht erzwungen werden kann, bietet eine solche Komponente keine Input-Ports an (s. Abb. 4.9).
Bei gewissen Ereignissen ist es jedoch nicht nur wichtig dass es aufgetreten ist, sondern auch was genau passiert ist. Das Ereignis liefert in diesem
Fall noch einen Wert mit, der die Art des Ereignisses näher beschreibt. Ein
dimmbares Licht, das als verteiltes Gerät abstrahiert werden kann, könnte
z. B. bei jeder Änderung der Dimmstufe ein Ereignis mit dem aktuellen
Dimm-Wert aussenden. Diese Situation in eine Komponente umzusetzen,
ist wie in Abb. 4.10 dargestellt möglich.
KAPITEL 4. ANFORDERUNGEN
33
Mit den vorgestellten zwei Arten von Komponenten (solche die Funktionen und solche die Ereignisse repräsentieren), lassen sich viele Szenarien
in einem verteilten System umsetzen, indem die Komponenten miteinander
gekoppelt werden, um zusammen eine neue Funktionalität zu definieren.
Komponentenfabrik
Um ein Schaltbild übersichtlich gestalten zu können, oder um (wie beim Array angeführt) verschiedene Kontexte zu realisieren, muss es möglich sein,
jede Komponente mehrfach zu integrieren. Dazu wird jede Komponentenart einer Komponentenfabrik untergeordnet, die für die Erstellung und das
Löschen dieser Komponentenart zuständig ist. Soll eine bestimmte Komponente zum Koppeln benötigt werden, wird eine Anfrage an die entsprechende
Komponentenfabrik gestellt, die eine neue Instanz der Komponente erstellt.
Diese Vorgangsweise entspricht dem Entwurfmuster Abstrakte Fabrik [8]. Die
Ports der Komponente können nun mit den Ports anderer Komponenten gekoppelt werden. Auf diese Art können z. B. mehrere Array-Komponenten in
das Schaltbild gebracht werden, die unterschiedliche Arrays repräsentieren.
Soll eine Komponente gelöscht werden, so wird auch das über die zugehörige Komponentenfabrik geregelt, die den Lösch-Befehl umsetzt und
evtl. notwendige Aufräumarbeiten durchführt.
4.1.2
Kopplungen
Wie bereits angesprochen und in Abb. 4.5 dargestellt, ist es möglich, Komponenten miteinander zu koppeln. Dabei werden Zuordnungen von Ports erstellt, die einerseits den Programmfluss, andererseits den Datenfluss definieren. Kopplungen betreffen also nicht Komponenten (zumindest nicht direkt),
sondern genauer betrachtet deren Ports. Je nach Port-Typ werden zwei
Kopplungsarten unterschieden: Daten-Kopplungen (DK) und Programmfluss-Kopplungen (PK). Erstere sind für den Transport von Daten zwischen
Daten-Ports zuständig, zweitere repräsentieren den Programmfluss. Sie geben also an, welche Funktion in Folge welcher anderen aufgerufen werden
soll, indem sie Programmfluss-Ports miteinander verbinden.
Abb. 4.11 zeigt den Wirkungsbereich der Kopplungen in einer etwas detailierteren Darstellung. Dabei ist ersichtlich, dass die DK die Daten nur bis
zur Hülle“ der Komponente transportieren. Ob damit intern eine entfernte
”
Funktion aufgerufen wird oder nicht, ist für die DK nicht weiter von Bedeutung. Selbiges gilt für die PKs: Sie aktivieren lediglich den Ziel-Port. Was
dieser dann weiter macht, betrifft die PK nicht mehr.
Bisher wurden immer nur Output-Ports an Input-Ports (aber nicht Output-Ports und Input-Ports jeweils untereinander) gekoppelt; für den Verlauf
der Arbeit wird diese Einschränkung beibehalten, denn sie sorgt für ein
konsistentes Erscheinungsbild der Kopplungen. Aus diesem Grund ist es
KAPITEL 4. ANFORDERUNGEN
34
Abbildung 4.11: Detailierte Darstellung von Komponenten. Die linke Komponente wird von einem Licht als Beobachter über Dimm-Wertänderungen
informiert und leitet dieses Ereignis an die Output-Ports weiter. Dort übernehmen die Kopplungen: Zunächst transportiert die DK den Dimm-Wert
zum unteren DIP der rechten Komponente, der den Inhalt eines Emails definiert, danach aktiviert die PK den PIP der Email-Komponente (hiermit
endet die Aufgabe der Kopplungen), worauf intern ein Email generiert wird
(mit der fixen Empfängeradresse bernhard.wally@fh-hagenberg.at“), das an
”
einen Email-Server weitergeleitet wird. Meldet der Email-Server den erfolgreichen Versandt des Emails, wird der DOP auf WAHR gesetzt, ansonsten auf
FALSCH. Schließlich wird der POP aktiviert.
auch nicht länger notwendig, die Kopplungen mit Pfeilen zu versehen, da die
jeweilige Richtung der Verbindungen durch Output- und Input-Port definiert
wird.
Konvertierer
Während PKs relativ unproblematisch sind, kann es bei DKs zu Komplikationen kommen, wenn die gekoppelten Ports auf verschiedenen Datentypen basieren. Zum Beispiel könnte der DOP eine Zeichenkette (String)
zur Verfügung stellen, der DIP aber nur mit Ganzzahlen (Integer) umgehen können. Die Problemlösung kann im DOP, im DIP oder in der DK
erfolgen. In dieser Arbeit ist es die DK, die mit einem Mechanismus ausgestattet wird, der Datentyp-Inkompatibilitäten durch Konvertierung der
Daten auflösen soll. Werden zwei Daten-Ports miteinander gekoppelt, kann
KAPITEL 4. ANFORDERUNGEN
35
die Kombination der Datentypen der beiden Ports zu einem der folgenden
vier Fälle führen:
• Identische Datentypen: Das ist der Idealfall, da hier keine weiteren
Vorkehrungen getroffen werden müssen. Der Wert eines Ausgangsparameters kann direkt für einen Eingangsparameter verwendet werden.
• Kompatible Datentypen: Der Datentyp des Ausgangsparameters
repräsentiert eine Teilmenge des Eingangsparameters. In diesem Fall
ist eine vollautomatische Konvertierung möglich. Ein Beispiel dafür ist
etwa das Überführen einer 2 Byte Ganzzahl in eine 4 Byte Ganzzahl:
Es findet kein Datenverlust statt.
• Konvertierbare Datentypen: Hierzu zählen Konvertierungen, die
mit einem potentiellen Datenverlust verbunden sind, wie etwa die Konvertierung einer Fließkommazahl in eine Ganzzahl. Ein anderes Beispiel ist die Konvertierung von boolschen Werten in Zahlenwerte, die
man z. B. so vornehmen könnte, dass eine 0 im Zahlenraum dem boolschen FALSCH-Wert entspricht, eine Zahl ungleich 0 dem WAHR-Wert.
Umgekehrt würde ein FALSCH in eine 0 und ein WAHR in eine 1 konvertiert werden. Für die in diese Kategorie fallenden Konvertierungen
lassen sich also Standard-Szenarien erfinden, die jedoch nicht immer
sinnvoll sind und gegebenenfalls angepasst werden müssen.
• Inkompatible Datentypen: Sämtliche Konvertierungen die nicht
ohne genaues Wissen des Kontexts durchgeführt werden können, fallen
hier hinein, etwa die Konvertierung einer Uhrzeit in einen boolschen
Wert. Um den Wert von einem Datentyp in den anderen überzuführen,
gibt es keine passende immergültige Konvertierung. Eine mögliche Umwandlung eines Zeit-Wertes in einen boolschen Wert könnte wie folgt
aussehen:
WENN zeit vor 16:00 DANN
gib WAHR zurück
SONST
gib FALSCH zurück
WENN_ENDE
Jede DK kann, wenn das notwendig ist, mit einem Konvertierer ausgestattet werden, der für die nötige Kompatiblität zwischen DOP und DIP
sorgt. Abb. 4.12 zeigt, wo sich der Konvertierer im Schaltbild befindet.
Mehrfachgekoppelte Ports
Die von einem DOP zur Verfügung gestellten Daten sind unter Umständen
nicht nur für einen DIP interessant, sondern für mehrere. Ebenfalls kann
es gewünscht werden, dass ein DIP seine Daten nicht nur von einem DOP
KAPITEL 4. ANFORDERUNGEN
36
Abbildung 4.12: Einbinden eines Konvertierers in die DK. (a) Zeigt die
Kopplung der Wecker- an die Lichtschalter-Komponente. Wenn die Weckzeit
vor 16:00 liegt, soll das Licht eingeschalten werden, ansonsten nicht. (b)
stellt den in (a) rot umrahmten Teil dar und zeigt, dass der Konvertierer
einen eingehenden Zeit-Wert in einen boolschen Wert umwandelt, um ihn
kompatibel mit dem DIP der Lichtschalter-Komponente zu machen.
Abbildung 4.13: Wird ein Email versendet, so wird der boolsche Rückgabewert dieser Funktion einerseits protokolliert, andererseits als Parameter für
ein Licht (zum Ein- und Ausschalten) verwendet. Sobald der Wecker läutet“,
”
wird die Uhrzeit protokolliert und das Licht ein- oder ausgeschalten, je nachdem welcher Wert derzeit dem DIP der Licht-Komponente zugewiesen ist.
bezieht. Die Mehrfachkopplung von Ports soll explizit erlaubt werden, um
keine funktionalen Einschränkungen zu riskieren. In Abb. 4.13 werden mehrfachgekoppelte Ports dargestellt.
Die Mehrfachkopplungen werfen neue Fragen auf: In welcher Reihenfolge
werden die DKs mit Daten versorgt? Was passiert, wenn zwei DKs gleichzeitig auf einen DIP zugreifen? Folgende Regeln werden dazu definiert:
• Die Reihenfolge in der DKs Werte vom DOP zugewiesen bekommen
ist nicht voraussagbar. Es ist aber auch nicht wichtig, ob eine DK
die Daten zuerst bekommt oder nicht, da die Komponente des DOPs
dafür zu sorgen hat, dass alle DKs ihre Werte an die entsprechenden
DIPs transportiert haben, bevor der POP der Ausgangskomponente
aktiviert wird und der Programmfluss weiterläuft.
KAPITEL 4. ANFORDERUNGEN
37
Abbildung 4.14: Wird der Wecker aktiv, so werden folgende Aktionen parallel (in separaten Threads) ausgeführt: Der Lichtschalter wird betätigt und
ein Email wird versandt. Das Email wird aber auch versandt, wenn sich
die Dimmstufe des Lichts verändert hat. Zur besseren Übersicht werden die
Daten-Kopplungen nicht dargestellt.
• Wenn mehrere DKs gleichzeitig schreibend auf einen DIP zugreifen,
so hat der DIP dafür zu sorgen, dass jede der Schreibaktionen atomar
abläuft, um unvorhersagbare Programmfehler zu vermeiden. Die Atomarität könnte durch Programmiersprachelemente wie Mutices oder
Semaphoren realisiert werden.
Doch nicht nur Daten-Ports können mehrfachgekoppelt werden, auch bei
Programmfluss-Ports sollen Mehrfachkopplungen möglich sein. Semantisch
entsprechen mehrere PKs, die von einem POP ausgehen einer Gabelung
des Programmflusses. Jede PK stellt einen neuen Thread dar; die Threads
laufen parallel ab und ermöglichen so das gleichzeitige Ausführen mehrerer Programmfluss-Stränge. Abb. 4.14 soll diesen Sachverhalt verdeutlichen.
Münden mehrere PKs in einen PIP, so entspricht das der Aktivierung des
PIPs von verschiedenen Threads aus.
Beispiel
Zu guter Letzt soll noch Abb. 4.15 einen Gesamteindruck über die Komponenten und Kopplungen bieten, indem ein etwas größeres Szenario umgesetzt
wird, das multiple Komponenteninstanzen, Schleifen und Mehrfachkopplungen beinhaltet.
4.2
Control
Die Manipulation der Komponenten und Verbindungen erfolgt über genau
spezifizierte, möglichst einfache Schnittstellen. So sollen etwa nur Basisdatentypen wie Zahlen und Zeichenketten zur Steuerung der Komponenten und
Verknüpfungen genügen, um auch von entfernten Hosts Steuerungstätigkeiten ohne allzuviel Aufwand durchführen zu können.
KAPITEL 4. ANFORDERUNGEN
38
Abbildung 4.15: Ändert sich die Dimm-Stufe des Lichtes, wird ein Array
mit Email-Adressen und eines mit Telefonnummern durchlaufen, nachdem
dessen Größe als Obergrenze der For-Schleife übernommen wurde, und für
jeden jeweiligen Eintrag ein Email bzw. ein SMS verschickt. Außerdem wird
der Dimm-Wert in einer Datei protokolliert. Daten-Kopplungen sind rot,
Programmfluss-Kopplungen schwarz dargestellt.
4.2.1
Komponenten
Die verfügbaren Komponentenfabriken müssen über einen Mechanismus einer Komponentenfabriks-Verwaltung bekannt gemacht werden, um diese
auch nutzen zu können. Den Komponentenfabriken werden dann Kommandos zum Erstellen und Löschen von Komponenteninstanzen übermittelt. Zu
beachten ist: Wird eine Komponente gelöscht, sind auch die Kopplungen
zugehöriger Ports zu löschen, da sie ohne die Ports ihre Gültigkeit verlieren.
Um das manuelle Setzen von DIP-Werten zu ermöglichen, muss der
Schreib-Zugriff auf diese ermöglicht werden. Ebenso soll es durch den Zugriff
auf PIPs möglich sein, Komponenten von Hand zu aktivieren.
Nachdem verteilte Geräte gekoppelt werden sollen, kann es vorkommen,
dass manche Geräte vorübergehend nicht zur Verfügung stehen. In diesem
Fall sollten bereits erstellte Komponenteninstanzen nicht einfach gelöscht,
sondern als offline markiert werden. Ist die betreffende Komponente zu einem späteren Zeitpunkt wieder verfügbar, so wird diese wieder als online
markiert. Diese Unterscheidung ist einerseits für den Benutzer wichtig, um
zu erkennen, dass gewisse Funktionalitäten evtl. nicht verwendet werden
können, andererseits wüsste dann auch die Komponente selbst, dass die entfernte Ressource, die sie ansprechen soll, nicht existiert und lässt den entfernten Funktionsaufruf bleiben. In dieser Situation versiegen Programmflüsse
– wenn sie in eine als offline markierte Komponente münden.
KAPITEL 4. ANFORDERUNGEN
4.2.2
39
Kopplungen
Die Steuerung der Kopplungen ist ähnlich jener der Komponenten: Kopplungen können erstellt und gelöscht werden. Weiters soll die Zuweisung eines
Konvertierers zu einer DK ermöglicht werden. Die Definition der Konvertierer soll zur Laufzeit (über eine Art Scripting-System) möglich sein, um
auftretende Probleme unkompliziert lösen zu können.
4.2.3
Schaltbild
Das erstellte Schaltbild soll als XML-Datei gespeichert und bei Bedarf wieder geladen werden können. Die zuvor definierten Komponenteninstanzen,
Kopplungen und Konvertierer sollen dabei automatisch wieder erstellt werden und ihren Dienst aufnehmen.
4.3
View
Die Darstellung der Komponentenfabriken, Komponenten, Kopplungen und
Konvertierern soll einerseits deren internen Zustand repräsentieren und andererseits Zugriff auf die Steuerung bieten, um Manipulationen vornehmen
zu können. Eine grafische Benutzeroberfläche könnte die Komponenten als
Blöcke mit Ein- und Ausgangs-Ports darstellen und die Verknüpfungen als
Linien zwischen den Ports, so wie das auch in vorangegangenen Abbildungen
gehandhabt wurde.
Um über den Zustand der Komponenten informiert zu werden, bietet
sich ein Ereignis-System an, bei dem die Darstellung als Beobachter auftritt.
Informationen über vorhandene oder nicht länger vorhandene Komponenten
und Komponentenfabriken können so der Darstellung ebenso übermittelt
werden, wie der momentan gültige Konvertierer einer Kopplung oder der
aktuelle Wert eines Daten-Ports. Die Darstellung kann auf diese Ereignisse
reagieren und muss sich nicht selbst um den aktuellen Zustand des Systems
kümmern. Somit wird die Zahl der Steuer-Aufrufe minimiert, da nur dann
Ereignisse gesendet werden, wenn auch tatsächlich etwas passiert ist. Würde
hingegen die Darstellung selbst verantwortlich sein, sich über den aktuellen
Zustand des Systems zu informieren, fielen wohl gelegentlich Anfragen an,
die keine Änderung des Systems feststellen würden.
Kapitel 5
Technologieauswahl
5.1
Grafische Programmierwerkzeuge
Die im vorigen Kapitel angeführten Anforderungen beschreiben im Grunde
ein grafisches Programmierwerkzeug, bei dem der Programmfluss durch das
Koppeln von Komponenten (der Ausdruck Komponente wird im weiteren
Verlauf synonym mit Funktionsblock verwendet) definiert wird. Da es bereits solche Applikationen gibt, sollen einige Eigenschaften existierender
Lösungen vorgestellt werden. Nachdem einige der Applikationen auch die
Möglichkeit bieten, eigene Funktionsblöcke zu definieren, wird überprüft,
ob es möglich ist, verteilte, dynamische Geräte (am Beispiel UPnP) als
Programmerweiterungen einzubinden. Die hier behandelten Applikationen
repräsentieren nicht eine vollständige Liste grafischer Programmiersysteme,
sondern wurden als Beispiele herausgegriffen.
5.1.1
Virtools Dev
Virtools Dev wird von Virtools1 vertrieben und bietet eine grafische Programmieroberfläche für interaktive 3D-Applikationen an, die Compositions
(dt. Kompositionen) genannt werden. In einer Komposition werden Funktionsblöcke, die Behaviour Building Blocks, gekoppelt, die die Parameter
der Kamera und der in der Szene vorhandenen Objekte sowie die Interaktionsmöglichkeiten definieren. Die Kopplungen müssen dabei nicht global
gelten (aber auch solche Kopplungen gibt es), sondern können für jedes Objekt gesondert definiert werden. Eine zu einem Objekt gehörende Menge
an Kopplungen (ein Objekt-gebundenes Schaltbild) von Building Blocks
wird ebenso Script genannt wie global geltende Kopplungen. Eine Komposition besteht also aus Szenen, die (globale oder Objekt-gebundene) Scripts
beinhalten, die wiederum Building Blocks und deren Kopplungen enthalten. Mehrere Building Blocks und die dazugehörenden Kopplungen können,
1
http://www.virtools.com/
40
KAPITEL 5. TECHNOLOGIEAUSWAHL
41
Abbildung 5.1: Die Building Blocks werden in Virtools als graue Boxen
dargestellt, die mit schwarzen (Behaviour Links) oder blau gestrichelten (Parameter Links) Linien verbunden werden.
um die Übersichtlichkeit zu erhöhen, zu einem einzigen zusammengesetzten Building Block zusammengefasst werden. Abb. 5.1 zeigt, wie Building
Blocks in Virtools Dev aussehen und wie diese gekoppelt werden können.
Virtools Dev unterscheidet bei Kopplungen zwischen solchen, die den
Programmfluss definieren (Behaviour Links) und solchen, die die Daten von
Building Block zu Building Block transportieren (Parameter Links). Die Daten können auf diesem Weg modifiziert und bei Bedarf Script-übergreifend
zur Verfügung gestellt werden.
Nachdem Virtools Dev für die Erstellung von 3D-Szenen entwickelt wurde, sind die Behaviour Links Frame-gesteuert. Alle Verknüpfungen von Building Blocks, die nicht explizit verzögert werden, werden innerhalb des selben
Frames berechnet. Als Entwickler einer Komposition ist man also dafür verantwortlich, dass rechenintensive Aufgaben über mehrere Frames verteilt
werden, um die 3D-Szene flüssig abspielen zu können.
Um das Repertoire der vorgegebenen Building Blocks zu erweitern, werden zwei Möglichkeiten angeboten [29]:
• Leichtgewichtige Building Blocks: Benutzer mit ein wenig Programmierkenntnissen haben die Möglichkeit eigene leichtgewichtige“
”
Building Blocks zur Laufzeit zu erstellen. Dazu gibt es einen eigenen Building Block, Run VSL, der es ermöglicht mittels der Virtools
Scripting Language (VSL) auf die Funktionen des Virtools Software
Development Kits (Virtools SDK – siehe Schwergewichtige Building
”
KAPITEL 5. TECHNOLOGIEAUSWAHL
42
Blocks“) zuzugreifen [32]. Für Run VSL gibt es einen integrierten Editor, der es erlaubt Ein- und Ausgangsparameter hinzuzufügen, zu entfernen und zu modifizieren. Der Typ der Parameter kann dabei aus
einer Liste von mehr als 60 Datentypen gewählt werden. VSL ist
von der Syntax her ähnlich wie C aufgebaut – wer also Erfahrung
mit C oder Scripting-Sprachen wie JavaScript hat, sollte sich schnell
mit VSL anfreunden können. Der Editor bietet eine Hervorhebung
von Schlüsselwörtern (engl. Syntax Highlighting), automatische Vervollständigung von Funktionsaufrufen (engl. Auto Completion) sowie
die Möglichkeit Abbruchstellen (engl. Break Points) zu definieren, um
das Debuggen des Scripts zu erleichtern. VSL-Scripts eignen sich vor
allem, um komplexe Parameter-Konvertierungen vorzunehmen oder
etwa Schleifen kompakt und übersichtlich zu implementieren.
• Schwergewichtige Building Blocks: Für Benutzer mit erweiterten Programmierkenntnissen eröffnet das Virtools SDK nahezu unbegrenzte Möglichkeiten für die Erweiterung von Virtools, sowie die
Gelegenheit, die Funktionalitäten von Virtools in eigenen Applikationen zu nutzen. Der wichtigste Anwendungsfall ist die Möglichkeit, eigene Building Blocks zu definieren. Diese können beliebigen C++ Code
ausführen und auch auf externe Bibliotheken zugreifen. Die definierten
Building Blocks werden einzeln oder gesammelt in Dynamic Link Libraries 2 (DLLs) kompiliert und diese in den Ordner BuildingBlocks
der Virtools Installation kopiert. Bei einem Neustart von Virtools Dev
werden die DLLs automatisch eingebunden, und die selbst erstellten
Building Blocks stehen zur Benutzung zur Verfügung.
Um z. B. eine Aktion eines UPnP-Gerätes ausführen zu können, gäbe es
unter anderem die Möglichkeiten
• einen generischen Building Block zu schreiben, der als Input-Parameter die ID der auszuführenden Action sowie die Eingangsparameter
in Form eines Arrays übernimmt und nach erfolgtem Aufruf die Ausgangsparameter als Array zur Verfügung stellt oder
• für jede UPnP-Aktion einen eigenen Building Block zu schreiben, der
diese Aktion genau repräsentiert und damit einen unkomplizierten
Umgang mit der UPnP-Aktion bietet.
Der Vorteil des generischen Building Blocks ist, dass damit beliebige
UPnP-Aktionen angesprochen werden können, auch wenn diese zur Entwicklungszeit des Building Blocks noch nicht bekannt sind. Die Nachteile
sind, dass
2
Für weitere Informationen zu DLLs siehe http://msdn2.microsoft.com/en-us/library/
1ez7dh12(vs.80).aspx
KAPITEL 5. TECHNOLOGIEAUSWAHL
43
• jeder Aktionsaufruf aufwändig auf- und nachbereitet werden muss,
da die Eingangsparameter zunächst in Array-Form gebracht werden
müssen und die Ausgangsparameter aus dem Array wieder ausgelesen
werden müssen, um sie in einem Script weiterzuverwenden, sowie
• die ID der Aktion dem Benutzer bekannt sein muss, um sie ansprechen
zu können.
Die Methode, für jede UPnP-Aktion einen eigenen Building Block zu
schreiben hat den Vorteil, dass der Building Block genau die Aktion repräsentiert (hinsichtlich der Anzahl und des Typs der Parameter), jedoch den
Nachteil, dass der Building Block im Voraus definiert worden sein muss.
Es ist also nicht möglich, zur Laufzeit neuentdeckte UPnP-Geräte in Scripts
einzubinden, sondern stattdessen muss zunächst ein entsprechender Building
Block als DLL kompiliert werden und anschließend Virtools neu gestartet
werden. Ein weiteres Problem stellen UPnP-Geräte dar, die bei einem Neustart ihre ID ändern. Der Building Block ist dann entweder unbrauchbar,
weil er nur für eine gewisse ID funktioniert, oder er benötigt einen weiteren
Eingangsparameter, mit dem die aktuelle ID des UPnP-Geräts eingestellt
werden kann, wodurch der Benutzungskomfort stark geschwächt wird, da
Details über das zu steuernde Gerät (die ID) bekannt sein müssen.
Beide Methoden sind unbefriedigend, da sie entweder zu unflexibel oder
zu kompliziert sind. Virtools Dev bietet leider keine Möglichkeit, zur Laufzeit dynamisch Building Blocks zu generieren und in der Benutzeroberfläche
zur Verfügung zu stellen oder diese wieder verschwinden zu lassen. Auch
gibt es keine Möglichkeit temporär abwesende Geräte visuell auszuzeichnen, um dem Benutzer intutiv mitteilen zu können, dass gewisse Ressourcen
nicht verfügbar sind. Bis auf die fehlende Dynamik ist die von Virtools Dev
verwendete Metapher für Building Blocks gut auf UPnP-Geräte übertragbar. Da fast alle Standard Building Blocks im Quellcode bei Virtools Dev
mitgeliefert werden und da es zum SDK eine ausgezeichnete Dokumentation
gibt, ist es möglich, die programmiertechnische Funktionsweise von Building
Blocks verstehen zu lernen.
5.1.2
Max
Max ist der Begriff für eine Familie von Produkten, die in der Tradition des
Patcher Editors [12] stehen, der über MIDI3 - und Steuersignale Klänge erzeugen konnte. Während Patcher lediglich mit MIDI-Daten umgehen konnte,
bieten die aktuellen Max-Produkte eine rigorose Echtzeit-Audiosignalverarbeitung an, wobei durch das Koppeln verschiedener Funktionsblöcke verschiedenste Klänge synthetisiert werden können. Die drei bekanntesten Pro3
Musical Instrument Digital Interface. Siehe auch: http://home.snafu.de/sicpaul/midi/
midi0a.htm
KAPITEL 5. TECHNOLOGIEAUSWAHL
44
Abbildung 5.2: Ein simpler Patch (links), der einen Sub Patch (links als
Object mit p“ bezeichnet) beinhaltet, der rechts dargestellt ist. Dieser Patch
”
lädt eine Audiodatei und spielt sie ab.
dukte sind PD4 , jMax5 und Max/MSP6 , die sich alle auf den Patcher Editor
zurückführen lassen [12, 27]. Während Max/MSP kommerziell von Cycling
747 vertrieben wird, stehen PD und jMax unter einer BSD8 -artigen Lizenz
bzw. der GNU GPL9 und sind inklusive Quellcode frei verfügbar.
Bei Max werden die Funktionsblöcke einfach Objects genannt, ein Schaltbild heißt Patch. Patches können abgespeichert werden und sind teilweise
unter den verschiedenen Produkten kompatibel. Die Kompatabilität hängt
dabei vom Vorhandensein der gekoppelten Objects im jeweiligen Produkt
ab. Um die Übersichtlichkeit zu wahren, können Teile eines Patches als Sub
Patch zusammengefasst werden, der wiederum aus Sub Patches bestehen
kann, usw. (s. Abb. 5.2) [26].
Jedes der Produkte kann durch externe Objects“ erweitert werden, und
”
so existieren u. a. Erweiterungen, die z. B. das Erstellen und Manipulieren
von 3D-Grafiken erlauben. Das Erstellen von externen Objects funktioniert
ähnlich wie bei Virtools Dev über ein SDK, mit dem diese in C10 erstellt
und kompiliert werden können.
Durch die Kombination der Erweiterungen mit den bereits vorhandenen mächtigen Funktionen der Audiosignalverarbeitung können auf diese
4
http://www.puredata.info/
http://freesoftware.ircam.fr/rubrique.php3?id rubrique=14
6
http://www.cycling74.com/products/maxmsp
7
http://www.cycling74.com/
8
http://www.opensource.org/licenses/bsd-license.php
9
GNU General Public Licence – die Lizenz für Open Source Software. Siehe auch:
http://www.gnu.org/copyleft/gpl.html
10
PD unterstützt auch C++ und Fortran.
5
KAPITEL 5. TECHNOLOGIEAUSWAHL
45
Art beeindruckende Multimediainstallationen geschaffen werden. Dadurch
finden Max-Produkte bei Live-Performances von Multimediakünstlern Verwendung. Dabei wird das jeweilige Max-Produkt als Werkzeug zur Signalverarbeitung verwendet, das einerseits die Klänge digitaler oder analoger
Klangquellen manipuliert und mit synthetischen Klängen mischt und andererseits vorbereitete Videos durch aus dem Audiosignal extrahierte Parameter künstlerisch verändert, mixt und steuert11 .
Sämtliche Max-Produkte weisen jedoch die selbe Schwäche wie Virtools
Dev auf: Erweiterungen (externe Objects) lassen sich nicht zur Laufzeit hinzufügen oder löschen, sondern müssen beim Programmstart als kompilierte
Bibliotheken zur Verfügung stehen. Die möglichen Workarounds sind gleich
wie bei Virtools Dev: Entweder man entwickelt ein generisches Object, das
beliebige UPnP-Aktionen ansprechen kann, oder pro UPnP-Aktion eines (s.
Abs. 5.1.1). Nachdem Max-Produkte auch eigene grafische Elemente zulassen, wäre es allerdings möglich, die erstellten Sub-Patches (die den Aufruf des generischen Objects kapseln) oder Objects (für die jeweilige UPnPAktion) grafisch über den aktuellen Verfügbarkeitsstatus des entsprechenden
UPnP-Geräts auszuzeichnen.
5.1.3
vvvv
Im Gegensatz zu Max spezialisiert sich vvvv12 nicht auf Echtzeit-Audioverarbeitung, sondern hauptsächlich auf die Echtzeit-Videosynthese [15].
Das Produkt wird von Meso 13 , einer Bürogemeinschaft in Frankfurt/Main,
entwickelt und steht für nicht-kommerzielle Projekte auf der Produkt-Website zum kostenlosen Download zur Verfügung [11]. vvvv wurde für Windows
entwickelt und verwendet Graphics Device Interface14 (GDI) und DirectX15 Funktionen, um hochperformante Grafikverarbeitung zu gewährleisten.
Die grafische Benutzeroberfläche präsentiert sich so spartanisch wie nur
möglich: Startet man vvvv, öffnet sich ein leeres, graues Fenster, ohne Werkzeug- oder Menüleiste. Sämtliche Funktionen sind in Menüs und Auswahllisten versteckt, die über verschiedene Mausklicks aktiviert und deaktiviert
werden können. Hat man sich an die ungewohnte Navigation gewöhnt, ist
ein sehr effizientes Arbeiten möglich. Durch die fehlenden Leisten bietet das
Fenster weiters die maximale Fläche an, auf der die Funktionsblöcke, Boxes
oder Nodes genannt, angeordnet werden können (s. Abb. 5.3).
11
Unter http://www.cycling74.com/section/artists können Videos von Multimediainstallationen und Live-Performances angesehen werden, die mit Max/MSP als Steuerzentrale
arbeiten.
12
http://vvvv.meso.net/
13
http://www.meso.net/
14
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/wingdistart 9ezp.
asp
15
http://www.microsoft.com/windows/directx/
KAPITEL 5. TECHNOLOGIEAUSWAHL
46
Abbildung 5.3: Ein Patch, der links eine (sinnlose) Addition beinhaltet und
rechts einen interaktiven GDI-Renderer, der die Textgröße abhängig von der
y-Koordinate der Maus skaliert.
Tabelle 5.1: Namensgebung der Elemente verschiedener grafischer Programmierumgebungen.
Produkt
Komponente
Virtools
Dev
Max
vvvv
Building Block
Object
Box/Node
Kopplung
Schaltbild
Behaviour Link,
Parameter Link
Patch Cord
Connection
Script, Composition
Patch, Sub Patch
Patch, Sub Patch
Nachdem für vvvv keine Erweiterungen programmiert werden können, ist
eine Einbindung von UPnP-Geräten nur indirekt möglich. UPnP-Aktionen
könnten über die HTTP-Box ausgeführt werden, die Rückgabeparameter
müssten in weiterer Folge aus der Aktions-Antwort des UPnP-Geräts ausgelesen werden. Das Problem bei dieser Methode ist, dass das Vorhandensein
ebenso wie der URL des Gerätes bekannt sein muss. Der interessante Aspekt
von UPnP, das automatische Erkennen von UPnP-Geräten im Netzwerk,
verliert dabei jedoch ebenso seinen Zweck wie die Eigenschaft von verteilten
Systemen, dass diese das darunterliegende Netzwerk abstrahieren.
5.1.4
Fazit
Tabelle 5.1 listet eine Gegenüberstellung der Namen der Elemente der angeführten grafischen Programmierumgebungen auf, um die Begrifflichkeiten
zu verdeutlichen.
KAPITEL 5. TECHNOLOGIEAUSWAHL
47
Alle vorgestellten Programme weisen die selbe Eigenschaft auf: Sie unterstützen das dynamische Hinzufügen der Funktionsblöcke nicht, was aber
gerade bei verteilten Geräten interessant wäre. Aufgrund der dynamischen
Natur verteilter Systeme kann über die Verfügbarkeit und Menge der verteilten Geräte nicht immer im Voraus eine Aussage getroffen werden. Ein
Programm, das die Vernetzung verteilter Geräte ermöglicht, sollte jedoch
diese Dynamik auch in der grafischen Benutzeroberfläche widerspiegeln um
so dem Benutzer auf einen Blick den aktuellen Zustand des Systems zu vermitteln.
Für den eigenen Prototypen wird daher eine eigene Applikation entwickelt, die basierend auf den Konzepten der vorgestellten grafischen Programmierumgebungen ähnliche Funktionalitäten bereitstellen und zusätzlich
die Dynamik verteilter Anwendungen ausreichend unterstützen soll.
5.2
Programmiersprache
Nicht unbedingt notwendiger Weise, aber aus ästhetischem“ Interesse soll
”
die zu entwickelnde Applikation plattformunabhängig sein. Nachdem in einer
verteilten Anwendung die verteilten Geräte auf unterschiedlichen Plattformen realisiert sein können, passt es gut dazu, wenn auch die Steuereinheit
nicht auf eine bestimmte Plattform festgelegt ist. Aufgrund der positiven
Programmiererfahrung bieten sich C++ oder Java als Programmiersprachen an, wobei in C++ die wxWidgets16 -Bibliothek die Entwicklung einer plattformunabhängigen grafischen Benutzeroberfläche ermöglichen soll.
wxWidgets ist ein Open Source Projekt und wird unter einer leicht modifizierten17 GNU Library General Public License18 (LGPL) vertrieben, die
dem Anwender der Bibliothek zusätzliche Rechte einräumt.
Sowohl für C++, als auch für Java existieren frei verfügbare UPnPImplementierungen, die die Kommunikation mit UPnP-Geräten drastisch
vereinfachen. Dazu gehören z. B. das Intel UPnP SDK 19 , Cyberlink 20 und
UPnPLib 21 .
Nachdem im Vorfeld bereits einige thematisch verwandte Projekte in
Java entwickelt worden sind, bietet sich Java als Programmiersprache für
den eigenen Prototypen an. Ein zusätzliches Argument für Java ist die
Verfügbarkeit des OSGi-Frameworks (die OSGi-Spezifikation wurde für Java
entwickelt), da es
16
http://www.wxwidgets.org/
http://www.wxwidgets.org/about/licence3.txt
18
Auch: GNU Lesser General Public License. Siehe auch: http://www.gnu.org/licenses/
lgpl.html
19
Für Java und C++. Siehe auch: http://www.intel.com/technology/upnp/
20
Für Java C, C++ und Perl. Siehe auch: http://www.cybergarage.org/
21
Für Java. Siehe auch: http://www.sbbi.net/site/upnp/
17
KAPITEL 5. TECHNOLOGIEAUSWAHL
48
• explizit für dynamische Anwendungen konzipiert wurde und daher als
Applikationsgrundlage mehr als geeignet erscheint und
• die nachträgliche Installation weiterer Technologien und Protokolle zur
Laufzeit ermöglicht.
Mit Swing22 steht weiters eine umfangreiche, an die eigenen Bedürfnisse
leicht anpassbare Grafik-Bibliothek zur Verfügung.
Die Entscheidung fällt somit zugunsten von Java. Als OSGi-Implementierung wird Equinox (s. Abs. 3.3.4) aus folgenden Gründen ausgewählt:
• Die Qualität scheint sehr hoch zu sein, da es als Referenzimplementierung für die aktuelle OSGi Release 4 gilt.
• Nachdem Eclipse-Plugins seit Version 3.0 als OSGi-Bundles zu entwickeln sind und Eclipse ein eigenes Plugin Development Environment
(PDE) zur Entwicklung von Plugins anbietet, werden gewisse Hilfestellungen in der Entwicklung von Bundles (vor allem beim Management
des Manifests) gegeben.
• Eclipse bietet eine eigene Konfiguration an, dank der ausgewählte
Bundle-Projekte mit einem Mausklick in einem Equinox-Framework
gestartet werden können.
• Die oben erwähnte Equinox-Umgebung kann auch im Debug-Modus
gestartet werden, was das Finden von Fehlern stark beschleunigt.
• In bisherigen Projekten stellte sich Equinox als zuverlässige Plattform
dar, mit der es keinerlei Probleme gab.
22
Teil der Java Foundation Classes: http://java.sun.com/products/jfc/. Eine detailierte
Einführung gibt es unter http://java.sun.com/docs/books/tutorial/uiswing/index.html
Kapitel 6
Umsetzung
Die Umsetzung des Prototyps, für den der Name Torem 1 gewählt wird,
findet in folgender Entwicklungsumgebung statt:
• Betriebssystem: Windows XP Professional2 und Gentoo Linux3
• Programmiersprache: Java 2 Standard Edition (J2SE) 5.0
• OSGi-Framework: Equinox (zuletzt: Equinox-3.2.0.v20060601)
Da ein OSGi-Framework als Applikationsgrundlage dient, wird das Gesamtsystem in mehrere Bundles heruntergebrochen, die gewisse Teilaufgaben
übernehmen (s. Abb. 6.1). Dabei lassen sich die Bundles in zwei Kategorien
unterteilen:
• Kern-Bundles repräsentieren Model und Control, wobei die ModelImplementierung mit zwei unterschiedlichen Ansätzen verfolgt wird:
Das Component- und das Converter-Bundle stellen lediglich Interfaces
zur Verfügung, die das Model beschreiben; konkrete Implementierungen müssen von Zusatz-Bundles verfügbar gemacht werden. Das Linkund das Position-Bundle definieren ihrerseits das Model, Kopplungen
bzw. Koordinaten, komplett – Erweiterungen durch Zusatz-Bundles
sind nicht möglich.
Die Implementierung der Control erfolgt in Form von Manager-Klassen
die als Dienste im OSGi-Framework registriert werden, um von anderen Kern- und Zusatz-Bundles genutzt werden zu können.
• Zusatz-Bundles dienen dazu, zusätzliche Funktionalitäten in Torem
einzubringen. Das können einerseits Model- und andererseits ViewImplementierungen sein.
1
Dieser Name hat keine besondere Bedeutung und ist auch keine Abkürzung.
http://www.microsoft.com/
3
http://www.gentoo.org/
2
49
KAPITEL 6. UMSETZUNG
50
Abbildung 6.1: Aufbau des Prototyps. Die Kern-Bundles stellen Dienste
zur Verfügung, die von anderen Bundles genutzt werden können, um SteuerKommandos abzugeben. Durch Zusatz-Bundles kann zusätzliche Funktionalität in das System eingebracht werden.
Die Manager können von Bundles, die der View-Schicht entsprechen,
benutzt werden, um Manipulationen der jeweiligen Models durch den Benutzer zu veranlassen. Innerhalb der Kern-Bundles kommunizieren die Manager untereinander, um das System konsistent zu halten. Zusatz-Bundles
lassen sich in beliebiger Zahl installieren und sind sofort nach der Installation verfügbar – es ist nicht notwendig, einen Neustart des Frameworks
vorzunehmen. Das OSGi-Framework erlaubt es auch, installierte Bundles
zu stoppen und später wieder neu zu starten. Dadurch lässt sich z. B. der
Wegfall von System-Ressourcen simulieren. Es ist weiters möglich, installierte Bundles zur Laufzeit zu aktualisieren, um z. B. fehlerhafte Bundles
durch fehlerbereinigte zu ersetzen.
Das Zusammenspiel von Model, View und Control in Torem wird in Abb.
6.2 dargestellt: Das Model wird ausschließlich über Steuerbefehle (engl. Control Commands) der Control manipuliert, die diese entweder selbsttätig
ausführt oder die von der View verlangt werden. Die View bekommt die
Informationen, die sie benötigt, um die korrekte Darstellung des Models zu
garantieren, über Events mitgeteilt, die entweder von der Control oder vom
Model selbst stammen. Für Probleme, die die Control nicht alleine lösen
kann, gibt es auch noch einen Mechanismus, der es erlaubt, einen Benutzer nach Lösungsvorschlägen zu fragen (engl. User Request). Die View teilt
der Control die Benutzerantwort (engl. User Response) mit, die sie dann
weiterverarbeitet.
KAPITEL 6. UMSETZUNG
51
Abbildung 6.2: Die MVC-Architektur von Torem.
6.1
Kern-Bundles
Da die Kern-Bundles jeweils nur aus einem Java-Package (dt. Paket) bestehen, wird zu Beginn jeder Bundle-Beschreibung der Name des Packages
angeführt. Im Text genannte Klassen werden in weiterer Folge nicht voll
qualifiziert angegeben – die Java-Package-Deklaration entspricht somit der
import-Anweisung einer Klassendefinition. Der Name der Kern-Bundles, unter denen sie im OSGi-Framework registriert werden, entspricht ebenfalls
dem Package-Name. Die Quelldateien der beschriebenen Klassen befinden
sich auf der beigelegten CD in folgendem Verzeichnis:
/torem/source/<BundleName>/OSGI-OPT/<PackagePfad>/.
6.1.1
Component-Bundle
Java-Package: net.bebedizo.torem.component
Das Component-Bundle ist für die Umsetzung der Anforderungen an Model und Control der Komponenten zuständig, die in Abs. 4.1.1 bzw. 4.2.1
definiert wurden. Während die Control vollständig implementiert wird, werden für das Model lediglich Interfaces definiert. Es ist die Aufgabe von
Zusatz-Bundles, konkrete Implementierungen vorzunehmen und dem OSGiFramework zuzuführen.
Für die Umsetzung werden die englischen Begriffe der in Kap. 4 definierten Elemente verwendet, die folgendermaßen lauten: Component für die
Komponente, Component Factory (CF) für die Komponentenfabrik, Port
für den Port und Component Manager (CM) für die Umsetzung der Control. Die Beziehungen dieser Begriffe soll Abb. 6.3 verdeutlichen, in der auch
die Schnittstellen zu View-Implementierungen berücksichtigt sind.
KAPITEL 6. UMSETZUNG
52
Abbildung 6.3: Überblick über das Component-Bundle.
Model
Das Model des Component Bundles setzt sich aus den Components, den CFs
und den Ports zusammen. Nachdem Torem in einer verteilten dynamischen
Umgebung läuft, ist es nicht sinnvoll, eine generische Implementierung zu
erstellen, die den Zugriff auf beliebige Ressourcen erlauben würde. Stattdessen werden Interfaces definiert, die von Zusatz-Bundles implementiert
werden können, um CFs (und damit Components und Ports) in Torem zu
integrieren. An dieser Stelle sei nur das Zusammenspiel dieser Komponenten
beschrieben.
Eine CF ist verantwortlich für das Erstellen, Löschen und Verwalten
von Components und sollte immer nur eine Art von Components erzeugen
(die Notwendigkeit einer CF wurde bereits in Abs. 4.1.1 beschrieben). Sie
repräsentiert eine Art von Funktionalität, die aber erst durch das Anlegen von Component-Instanzen genutzt werden kann. Um eine CF in Torem
verfügbar zu machen, genügt es, diese als Dienst im OSGi-Framework zu registrieren (das ist die Aufgabe von Zusatz-Bundles). Der CM wird darüber
automatisch informiert, sowie er auch erfährt, wenn ein Zusatz-Bundle eine
CF wieder entfernt. Eine registrierte CF bekommt vom CM eine eindeutige
ID in Form einer Long-Zahl zugewiesen.
Nachdem CFs von Zusatz-Bundles eingebracht werden, sind auch diese
dafür verantwortlich, die CFs aktuell zu halten. Ein Bundle, das z. B. den Zugriff auf UPnP-Geräte ermöglicht, muss dafür sorgen, dass CFs, die UPnPAktionsaufrufe oder UPnP-Statusvariablen kapseln, wieder entfernt werden,
sobald das zugehörige UPnP-Gerät nicht mehr im Netzwerk zur Verfügung
steht.
Die von einer CF erstellten Components erhalten ebenfalls vom CM
eine eindeutige ID in Form einer Long-Zahl und sind von außen betrachtet
nur eine Menge an Ports, die für Kopplungen verwendet werden können.
KAPITEL 6. UMSETZUNG
53
Die IDs der Ports werden Component-intern, als Strings, verwaltet – die
Ports verschiedener Components der selben CF haben also die selben IDs.
Auf semantischer Ebene werden zwei Kategorien von Ports unterschieden:
Programmfluss- und Daten-Ports. Jede der beiden Kategorien teilt sich wiederum in zwei Typen auf: Input- und Output-Ports. Das ergibt vier verschiedene Arten von Ports, die bei der Kopplung unterschiedlich behandelt
werden müssen (s. Abs. 6.1.2). Wird ein Port aktiviert oder bekommt einen
Wert zugewiesen, teilt er dies zwei Arten von Listeners, die sich bei Ports
registrieren können, mit:
• Port Listeners werden von den Kern-Bundles gestellt und dienen
dem internen Datentransfer von Output- zu Input-Port und von InputPort zu Component. Ein Port Listener bekommt lediglich den Namen
des Ports sowie den aktuellen Wert mitgeteilt.
• Port Event Listeners werden mittels Port Events informiert, in die
das entsprechende Port-Objekt integriert ist. Sie dienen der Aktualisierung von View-Implementierungen.
Eine Component registriert sich bei ihren Input-Ports als Port Listener
und kann auf Port-Aktivierungen und -Wertzuweisungen beliebig eingehen.
Gewöhnlich wird eine Component auf die Wertzuweisung eines DIPs damit
reagieren, dass sie diesen Wert selbst zwischenspeichert. Die Aktivierung
eines PIPs wird hingegen das Ausführen der durch die Component beschriebenen Funktion zur Folge haben.
Für die Implementierung einer Component gibt es (abgesehen vom Interface Component, das implementiert werden muss) keine verpflichtenden Bestimmungen, um die durch Components umsetzbaren Szenarien nicht einzuschränken. Sofern es möglich ist, sollten jedoch folgende Regeln eingehalten
werden, da so dem Benutzer ein konsistentes Erscheinungsbild geboten wird
und Missverständnisse vermieden werden können:
• Wird ein PIP aktiviert, wird irgendwann als Reaktion darauf genau ein
zugewiesener POP aktiviert (der Programmfluss soll nicht versiegen“
”
und sich auch nicht teilen).
• Stellt eine Component DOPs zur Verfügung, so werden die DOPs vor
dem POP aktiviert, um sicherzustellen, dass die Daten an gekoppelte
DIPs weitergeleitet werden, bevor der Programmfluss weitergeleitet
wird.
Für CFs und Components gibt es je eine abstrakte Implementierung
(ComponentFactoryPrototype bzw. AbstractComponent), die das Programmieren einer eigenen CF bzw. Component stark vereinfachen, sofern die eigenen
Klassen davon abgeleitet werden. Für Ports steht eine vollfunktionstüchtige
Implementierung mit der Klasse PortImpl zur Verfügung. Beispiele zum Erstellen eigener CFs und Components folgen in den Abs. 6.3.1 und 6.3.2.
KAPITEL 6. UMSETZUNG
54
Control
Die Control des Component-Bundles wird vom CM übernommen, der sich
als Dienst im OSGi-Framework registriert. Der CM ist unter anderem dafür
verantwortlich, zu erkennen, welche CFs derzeit online, und welche offline
sind. Die Initiative bei einem Statuswechsel der CFs geht dabei von den CFs
aus – der CM muss lediglich darauf reagieren.
Um dem CM CFs zur Verfügung zu stellen, wird wiederum der DienstMechanismus des OSGi-Frameworks herangezogen. Der CM wird informiert,
sobald eine CF als Dienst registriert wird, oder sich wieder abmeldet. Das
OSGi-Framework übergibt dabei jeweils eine Referenz auf die registrierte
oder abgemeldete CF. Der CM reagiert auf diese Nachrichten jeweils unterschiedlich:
• Wenn sich eine CF abmeldet, wird geprüft, ob diese – noch immer
vorhandene – Component-Instanzen erzeugt hat. Ist das der Fall, so
wird die CF und alle erzeugten Components als offline markiert. Ist
das aber nicht der Fall, so wird sie ohne weiteren Verwaltungsaufwand
aus dem CM gelöscht und steht nicht länger zum Instanzieren von
Components zur Verfügung.
• Wenn eine CF registriert wird, wird zunächst überprüft, ob es eine
als offline markierte (alte) CF gibt, die dieser entspricht. Die Prüfung
erfolgt in zwei Schritten, die weiter unten erläutert werden. Existiert
eine entsprechende CF, so wird die alte durch die neue ersetzt und die
erzeugten Components der alten werden durch entsprechend erzeugte
Component-Instanzen der neuen ersetzt. Die ersetzten Components
und die neue CF werden als online markiert. Existiert keine entsprechende CF, so wird die neue CF einfach der Menge an bereits vorhandenen hinzugefügt und kann verwendet werden, um Components zu
erzeugen.
Um herauszufinden, ob eine neu registrierte einer als offline markierten
CF entspricht, werden zwei Stufen der Übereinstimmung definiert. Die eine
besagt, ob zwei CFs gleich (engl. equal), die zweite, ob die CFs einander
ähnlich (engl. similar) sind. Gleichheit wird automatisch verarbeitet und die
neue CF ersetzt die als offline markierte. Sind zwei CFs einander jedoch nur
ähnlich, so muss ein Benutzer in die Entscheidung einbezogen werden, ob die
neue CF die alte ersetzen soll. Die Kriterien für Gleichheit und Ähnlichkeit
werden als Schlüssel-Wert-Paare in jeder CF gespeichert und sind von dort
über die Methoden getEqualities bzw. getSimilarities abrufbar.
Der Grund, warum der Begriff der Ähnlichkeit überhaupt eingeführt
werden muss, liegt darin, dass die UPnP-Spezifikation vorsieht, dass jedes
UPnP-Gerät eine einzigartige ID haben muss. Diese Definition führt dazu,
dass einige Geräte beim Start eine zufällig generierte Zeichenkette als ID benutzen, was zur Folge hat, dass ein und das selbe Gerät bei jedem Neustart
KAPITEL 6. UMSETZUNG
55
eine neue ID erzeugt. Eine strenge Gleichheits-Prüfung würde ein neugestartetes Gerät aufgrund der unterschiedlichen ID als unterschiedlich ansehen
und keine Ersetzung vornehmen, was u. U. nicht im Sinne des Benutzers ist.
Andererseits würde ein Nichtbeachten der ID dazu führen, das Geräte, die
sich beabsichtigterweise nur aufgrund ihrer ID unterscheiden, als gleich erkannt würden. Die Möglichkeit, den Benutzer entscheiden zu lassen, scheint
eine gute Möglichkeit zu sein, um dieses Problem zu umgehen.
Um die Benutzerabfrage durchführen zu können, muss mindestens ein
User Request Event Listener im OSGi-Framework registriert sein. Jeder der
Listener wird um Rat bezüglich der Gleichheit gefragt, und sobald einer der
Listener antwortet, wird die CF dementsprechend gesetzt.
View
Um eine View für das Component-Bundle zu implementieren, sollten folgende Interfaces genauer betrachtet werden:
• ComponentManager zum Weiterleiten von Steuerbefehlen an CFs, Components und Ports; ist als Dienst im OSGi-Framework registriert.
• ComponentEventListener und PortEventListener sind zu implementieren, um über den aktuellen Zustand des Models informiert zu werden.
• UserRequestEventListener, um dem Benutzer die Möglichkeit zu geben, Ähnlichkeitsproblematiken zu lösen.
6.1.2
Link-Bundle
Java-Package: net.bebedizo.torem.link
Das Link-Bundle implementiert Model und Control der Kopplungen, die
zwischen Ports hergestellt werden können, wobei in der Implementierung
der engl. Begriff Link für Kopplung gewählt wird. Abb. 6.4 zeigt die Hauptbestandteile dieses Bundles.
Model
Ein Link (vollständig implementiert in der Klasse LinkImpl) dient der Kopplung eines DOPs mit einem DIP (Daten-Link) oder eines POPs mit einem PIP (Programmfluss-Link). Mischformen (DOP mit PIP oder POP
mit DIP) sind ebensowenig zulässig, wie das Koppeln von Input-Ports und
Output-Ports jeweils untereinander (s. Abs. 4.1.2). Die Unterscheidung zwischen Programmfluss- und Daten-Link geschieht auf einer rein semantischen
Ebene. Programmiertechnisch sind die beiden Links äquivalent, wobei beim
Programmfluss-Link als zu übertragendes Datum immer null herangezogen
wird. Ein Link registriert sich als Port Listener bei dem Output-Port, der
KAPITEL 6. UMSETZUNG
56
Abbildung 6.4: Die wichtigsten Bestandteile des Link-Bundles.
das Datum bereitstellt, das an einen Input-Port weitergeleitet wird. Sobald
ein Datum an den Input-Port transportiert wurde, werden registrierte Link
Event Listeners mittels eines Link Events darüber informiert.
Wie in Abs. 4.1.2 erwähnt, müssen Daten-Links gegebenenfalls Konvertierungen vornehmen. Dazu kann jedem Link ein Konvertierer (s. Abs. 6.1.3)
zugeteilt werden, der vom Link aufgerufen wird, bevor das Datum an den
DIP weitergeleitet wird. Ein Link prüft, sobald er angelegt wurde, oder jedesmal wenn ihm ein Konvertierer zugeteilt wurde, ob die Datentypen der
Ports und (falls vorhanden) des Konvertierers zueinander kompatibel sind.
Danach wird ein entsprechendes Link Event an registrierte Listener versandt.
Ein Programmfluss-Link startet zur Aktivierung eines PIPs jedesmal
einen neuen Thread (dt. Faden oder Ausführungsstrang [40]). Der Grund
dafür soll rasch erläutert werden: Ein PIP informiert seine Component über
die Methode portActivated darüber, dass nun die Component-spezifische
Funktionalität auszuführen ist. Innerhalb von portActivated wird dann ein
POP aktiviert, der über einen Programmfluss-Link wieder einen PIP aktiviert, usw. Würde die Aktivierung des PIPs nicht in einem eigenen Thread
geschehen, würden sich die Methodenaufrufe ineinander schachteln und den
Speicher des Computers auffüllen, bis ein Ende des Programmflusses kommt.
Im Falle einer Schleife im Schaltbild ist dies jedoch nie der Fall, und deswegen erfolgt der Aufruf des PIPs in einem neuen Thread, da dadurch das
Ineinanderschachteln verhindert wird.
Control
Der Link Manager (LM) dient dem Erzeugen und Löschen von Links sowie
dem Zuweisen eines Konvertierers zu einem Link. Um einen Link anlegen
zu können, werden dem LM die IDs der zu verbindenden Ports sowie die
der zugehörigen Components mitgeteilt. Er sucht sich daraufhin vom CM
KAPITEL 6. UMSETZUNG
57
die entsprechenden Port-Instanzen und registriert den Link als Port Listener
beim Output-Port. Den zu koppelnden Input-Port speichert der Link intern
ab, um Programmfluss und Daten weiterleiten zu können.
Der LM wird seinerseits auch vom CM aufgerufen, falls eine Component
gelöscht wird. Der CM sucht sich in diesem Fall alle Links, die mit Ports
dieser Component verbunden waren, heraus und teilt dem LM mit, das diese
Links zu löschen seien.
Eine weitere wesentliche Funktionalität wurde dem LM zugeteilt: Das
Speichern und Laden des erstellten Schaltbildes, für das im weiteren Verlauf der Begriff Mapping verwendet wird. Zum Speichern werden alle aktuell
erzeugten Components und deren CFs sowie alle Links und deren Konvertierer in einen XML-String gepackt, der dann von einer View als XML-Datei
gespeichert werden kann. Um ein Mapping zu laden, wird dem LM ein entsprechender XML-String übergeben. Dieser löscht daraufhin zunächst alle
bestehenden Components und Links und erstellt anschließend neue, gemäß
der XML-Definition. Um die Wiederherstellung möglichst benutzerfreundlich durchführen zu können, werden in das Mapping auch die Koordinaten,
an denen sich die einzelnen Components in der View befinden (s. Abs. 6.1.4),
sowie die Werte, die den Ports zum Zeitpunkt des Speicherns zugewiesen
sind, gespeichert. Dadurch wird beim Laden einerseits das Layout und andererseits die Zuordnung der Werte zu den Ports, die andernfalls mit null
initialisiert würden, sichergestellt. Dabei ist zu beachten, dass alle im Mapping definierten CFs zum Zeitpunkt des Ladens auch tatsächlich vorhanden
sein sollten. Fehlt eine Ressource, so wird das Mapping nicht vollständig
geladen.
Das XML-Schema für die XML-Beschreibung eines Mappings ist auf der
CD unter dem Pfad /torem/mapping.xsd einsehbar.
View
Eine View, die das Link-Bundle repräsentieren soll, muss vor allem die zwei
folgenden Interfaces beachten:
• LinkManager zum Weiterleiten von Steuerbefehlen an Links, sowie zum
Laden und Speichern erstellter Mappings; ist im OSGi-Framework als
Dienst registriert.
• LinkEventListener kann implementiert werden, um über den aktuellen
Zustand des Models informiert zu werden.
Nicht vernachlässigt werden sollte die Tatsache, dass Links nur in Verbindung mit Components und deren Ports einen Sinn ergeben. Es ist daher sinnvoll, in einer View-Implementierung Links in Kombination mit den
betroffenen Components darzustellen, und somit auch die Interfaces des
Component-Bundles (s. Abs. 6.1.1) nicht außer Acht zu lassen.
KAPITEL 6. UMSETZUNG
58
Abbildung 6.5: Das Converter-Bundle.
6.1.3
Converter-Bundle
Java-Package: net.bebedizo.torem.converter
Das Converter-Bundle sorgt für die Einbindung von Konvertierern, in weiterer Folge Converters genannt. Die Verwaltung der Converters wird vom
Converter Manager übernommen. Abb. 6.5 gibt einen Überblick über die
Elemente, die in diesem Bundle definiert werden.
Model
Die zu verwaltenden Objekte in diesem Bundle sind die Converters. Jeder
Converter repräsentiert einen bestimmten Algorithmus, der die Konvertierung eines Objekts von einem Datentyp in einen anderen (oder auch wieder
denselben) ermöglicht. In Java-Syntax ausgedrückt bedeutet es, dass er die
Methode public Object convert( Object value ); des Interfaces Converter
implementieren muss. Ein Converter wird durch den Input- und den OutputDatentyp sowie die convert Methode definiert. Ein Beispiel für einen Converter, der einen Wert von einer Zeichenkette (String) in eine Gleitkommazahl
(Float) umwandelt, ist:
// ...
public Float convert ( Object value )
{
return Float . parseFloat ( ( String ) value ) ;
}
// ...
Control
Die Control der Converters wird vom Converter Manager übernommen.
Dieser bietet die Möglichkeit, Converters hinzuzufügen und zu löschen. Das
Hinzufügen kann auf zwei unterschiedliche Arten erfolgen:
KAPITEL 6. UMSETZUNG
59
• Über ein Zusatz-Bundle, das Converters als Dienste im OSGi-Framework registriert, oder
• indem man einen Converter-Namen und den Algorithmus (als String)
sowie den Input- und den Output-Datentyp (als Class-Objekte) dem
Converter Manager übergibt, der sich daraufhin den Converter selbst
erstellt (s. unten).
Der Converter Manager erstellt für jeden Link, zu der ein Converter
hinzugefügt werden soll, eine neue Instanz eines Converters. Darum speichert
er nur das Class-Object der hinzugefügten Converters und ruft bei Bedarf
die newInstance Methode auf. Jeder Converter muss demnach einen DefaultKonstruktor4 bereitstellen, damit dieser Aufruf funktioniert.
Das Erstellen eines Converters über den Converter Manager (mittels
der Methode createConverter) funktioniert über einen etwas komplizierteren Mechanismus, der in aller Kürze beschrieben werden soll: Beim Start
des Converter-Bundles legt der Converter Manager in einem Verzeichnis,
das ihm vom OSGi-Framework zur Verfügung gestellt wird, das Converter
Interface sowie eine abstrakte Implementierung (AbstractConverter – beinhaltet alles außer der convert Methode) als Java-Quelldateien ab und kompiliert diese mit dem Java Compiler von Sun5 . Die kompilierten Klassen
sind notwendig, um den Klassenpfad zu definieren, der für die nachfolgenden Converter-Kompilierungen gebraucht wird. Soll nun ein neuer Converter
geschaffen werden, so nimmt der Converter Manager die übergebenen Parameter (Input- und Output-Datentyp, Script sowie der Name für den Converter) und baut sich damit eine neue Klasse, zunächst in Form eines (langen) Strings, der den Quelltext der Klasse repräsentiert, zusammen. Diese
erweitert die zuvor erwähnte abstrakte Klasse. Den String speichert er anschließend als Datei ab und versucht sie – unter Zuhilfenahme des zuvor
erwähnten Klassenpfades – zu kompilieren. Ist die Kompilierung erfolgreich,
so wird die erstellte Klasse mittels eines java.net.URLClassLoaders geladen
und steht ab sofort zur Verfügung. Klappt die Kompilierung nicht, wird die
Zeile, wo ein Kompilierfehler vom Java Compiler angezeigt wurde, zurückgeliefert.
View
Eine View für das Converter-Bundle ist vor allem auf folgende zwei Interfaces
angewiesen:
• ConverterManager zum Erstellen und Löschen von Converters; ist als
Dienst im OSGi-Framework registriert.
4
5
Ein Konstruktor, der keine Parameter definiert.
Dieser liegt jedem JDK im JAR-Archiv <JDK>/lib/tools.jar als Java-Klasse bei.
KAPITEL 6. UMSETZUNG
60
Abbildung 6.6: Das Position-Bundle.
• ConverterEventListener sollte implementiert werden, um über hinzugefügte oder entfernte Converters informiert zu werden.
6.1.4
Position-Bundle
Das Position-Bundle speichert mit Hilfe des Position Managers die Koordinaten, die die instanzierten Components in der View-Implementierung
haben. Abb. 6.6 illustriert die Bestandteile des Position-Bundles.
Model
Die zu verwaltende Entität sind 2D-Koordinaten, die die Position der Components repräsentieren. Zur Verwaltung wird die Klasse java.awt.Point herangezogen.
Control
Der Position Manager verwaltet 2D-Koordinaten, die er Components zuweist. Nachdem Torem das gleichzeitige Vorhandensein mehrerer View-Implementierungen unterstützt, sorgt der Position Manager dafür, dass die
Components in allen Views an der selben Stelle sind.
View
Folgende Interfaces werden vom Position Bundle definiert und können von
View-Implementierungen verwendet werden:
• PositionManager zum Mitteilen und Erfragen der Koordinaten der
Components; ist im OSGi-Framework als Dienst registriert.
• PositionEventListener kann implementiert werden, um über geänderte Koordinaten informiert zu werden.
KAPITEL 6. UMSETZUNG
6.2
61
GUI-Komponenten
Die in diesem Abschnitt vorgestellten GUI-Komponenten sind als BeispielImplementierungen für die View-Schicht der MVC-Architektur zu sehen. Die
GUI-Bundles fallen in die Klasse der Zusatz-Bundles; sie sind für den Betrieb
von Torem also nicht unbedingt notwendig. Eigene View-Implementierungen
können anstatt der hier gelisteten eingebunden werden. Es ist möglich, nachdem mithilfe von GUI-Komponenten ein Mapping erstellt wurde, die GUIBundles zu stoppen, ohne den Betrieb der Kern-Bundles zu beeinflussen.
Bezüglich der Namesgebung der Bundles und der Position der Quelldateien
auf der CD gelten die selben Regeln wie in Abs. 6.1 festgehalten.
6.2.1
GUI-Basis
Java-Package: net.bebedizo.torem.gui
Als gemeinsame Basis für die anschließend definieren View-Implementierungen stellt dieses Bundle einen javax.swing.JFrame zur Verfügung, in den
weitere Bundles eigene Inhalte in Form von javax.swing.JPanels beisteuern
können. Der JFrame ist, wie in Abb. 6.7 dargestellt, in mehrere Bereiche
unterteilt, die jeweils als javax.swing.JTabbedPane implementiert werden,
wodurch mehrere Views pro Bereich als seperate Tabs (dt. Karteireiter)
hinzugefügt werden können, ohne sich visuell in die Quere zu kommen.
Startet man das Bundle ohne weitere GUI-Bundles, so ist der dargestellte JFrame leer. Erst durch zusätzliche Bundles werden die drei Bereiche
mit Inhalten gefüllt. Dazu müssen die Bundles Dienste registrieren, die diesem Bundle vom OSGi-Framework übermittelt werden. Je nach Art des
registrierten Dienstes wird dieser einem der drei Bereiche zugeordnet:
• ComponentFactoriesVisualizer werden dem Bereich zur Darstellung
der CFs (links oben) hinzugefügt,
• ComponentLinkVisualizer werden in der unteren Hälfte der Applikation
zur Anzeige gebracht und
• AllPurposeVisualizer werden rechts oben dargestellt.
Jeder dieser Dienste leitet sich von JPanel ab und wird in Form eines Tabs
in den entsprechenden Bereich eingegliedert. Wird ein Dienst wieder abgemeldet, so wird der zugehörige Tab gelöscht.
Um die Interoperabilität zwischen Views verschiedener Bundles zu gewährleisten, steht ein Listener-System zur Verfügung, das ebenfalls über
die Dienst-Infrastruktur des OSGi-Frameworks verwaltet wird. Vier unterschiedliche Listeners dienen dem Datenaustausch, der über Benutzeraktivitäten informieren soll:
KAPITEL 6. UMSETZUNG
62
Abbildung 6.7: Der hier dargestellte JFrame teilt sich in drei Bereiche, die
für die Anzeige unterschiedlicher Views geeignet sind. Der Bereich links oben
(gelb) soll Views zur Darstellung der verfügbaren CFs Platz bieten, rechts
davon (rot) befindet sich ein Bereich, der verschiedenste Views beinhalten
kann (z. B. eine Auflistung der definierten Converters). Die große Fläche unten (blau) ist für die Darstellung der Components und Links (des Mappings)
reserviert.
• ComponentFactorySelectionListener werden über die aktuell ausgewählte CF informiert,
• ComponentSelectionListener erhalten eine Benachrichtigung über die
aktuell im Mittelpunkt stehende Component,
• ConverterSelectionListeners wird eine Link-ID und die dazugehörige
Converter-ID übermittelt und
• LinkSelectionListener werden informiert, sobald ein Link die besondere Aufmerksamkeit des Benutzers hat.
Das Informieren der Listeners muss von jeder View selbst initiiert werden.
Soll ein komplexeres Interoperationsmuster realisiert werden, ist es empfehlenswert, von diesem Listener-System abzusehen und eigene Schnittstellen
für den View-übergreifenden Datentransfer zu definieren.
KAPITEL 6. UMSETZUNG
63
Menü
Unabhängig von den drei Bereichen enthält der JFrame ein Menü und eine
Werkzeugleiste. Die dadurch ausführbaren Aktionen sind bei beiden GUIElementen gleich – lediglich das Beenden der Applikation geht nur über das
Menü. Die redundaten vier Aktionen sind:
• Das Speichern des aktuell erstellten Mappings in eine beliebige Datei
(Speichern unter...),
• das Laden eines gespeicherten Mappings aus einer Datei (Öffnen...),
• das Speichern des aktuellen Mappings unter dem selben Namen, unter
dem es zuvor gespeichert oder von dem es geladen wurde (Speichern)
und
• das Löschen aller erstellten Components und Links, um wieder ein
leeres Blatt“ vor sich zu haben (Neu).
”
User Requests
Um Benutzeranfragen, die evtl. vom CM gestellt werden, beantworten zu
können, registriert sich das Bundle als UserRequestEventListener im OSGiFramework, was dazu führt, dass User Requests an dieses Bundle versendet
werden. Sobald ein User Request eintrifft, wird ein modaler Dialog geöffnet,
der dem Benutzer den Text des Requests präsentiert und ihm die Möglichkeit
gibt mit Ja“ oder Nein“ zu antworten. Die Antwort wird als boolscher
”
”
Wert interpretiert und an den Sender des Requests zurückgeleitet.
Lokalisierung
Um die grafische Benutzeroberfläche problemlos in mehrere Sprachen übersetzen zu können, holen sich alle Menüeinträge und die Tooltips6 der Werkzeugleisteneinträge ihre darzustellenden Strings aus einer Datei-basierten
Sprach-Datenbank. Diese fußt auf der Lokalisierungs-Infrastruktur (engl. Localization), die von Java über das java.util.ResourceBundle bereitgestellt
wird. Für jede Sprache wird eine eigene Datei mit einem Namen nach dem
Schema bundle_<Sprache>.properties erstellt, wobei <Sprache> der in [34]
und [4] dargestellten Form folgen muss, in der Schlüssel-Wert-Paare gespeichert werden.
Wird nun ein String zum Anlegen einer grafischen Komponente benötigt,
so wird über das ResourceBundle nach einem passenden Eintrag für die aktuelle Systemsprache gesucht. Wie in [4] ausgeführt, verläuft die Suche vom
Speziellen ins Generelle. Ein Beispiel: Angenommen, die aktuelle Systemsprache ist de_AT (Deutsch mit der Landeskennung Österreich) und es wird
6
Ein Tooltip ist eine Zeichenkette, die beim längeren Verweilen des Mauszeigers auf
einer JComponent auftaucht [40].
KAPITEL 6. UMSETZUNG
64
nach einem Wort für den Schlüssel Open“ gesucht, dann wird zunächst in
”
der Datei bundle_de_AT.properties, sofern diese vorhanden ist, nach einem
Eintrag gesucht (der könnte z. B. Mach’s auf“ lauten). Schlägt die Suche
”
fehl, ist die Datei bundle_de.properties an der Reihe. Gibt es auch diese
Datei nicht oder findet sich darin kein passender Eintrag (z. B. Öffnen“)
”
zum Schlüssel, wird die Ausweich-Datei bundle.properties zu Rate gezogen
(in der schließlich die englische Version gefunden wird: Open“).
”
Gemäß der Empfehlung in [22] werden die Lokalisierungs-Dateien im
Ordner OSGI-INF/l10n als bundle*.properties abgelegt. Der Unterordner
l10n steht für die gängige Abkürzung des englischen Wortes localization“
”
und bedeutet soviel wie l, dann 10 Buchstaben, dann n“.
”
Die Lokalisierung kann beim Start des OSGi-Frameworks auch über die
Kommandozeile definiert werden, wenn die systemweite Lokalisierung überschrieben werden soll. Es muss lediglich die Java-Systemeigenschaft osgi.nl
definiert werden, in der eine beliebige Lokalisierung angegeben werden kann
(z. B. -Dosgi.nl=de für Deutsch ohne Landeskennung).
6.2.2
Component Factories
Java-Package: net.bebedizo.torem.gui.componentfactory.all
Dieses Bundle definiert eine View zum Anzeigen aller verfügbarer CFs, die in
einer Liste dargestellt werden und dem Benutzer – durch einen Doppelklick
auf einen Listeneintrag – die Möglichkeit geben, eine Component von der zugehörigen CF erstellen zu lassen. ComponentFactorySelectionListeners werden aufgerufen, sobald ein Rechtsklick auf einen der Listeneinträge erfolgt.
Abb. 6.8 zeigt einen Screenshot der View in deutscher Lokalisierung.
Das Bundle registriert sich als ComponentFactoriesVisualizer im OSGiFramework und wird daher vom GUI-Basis-Bundle benachrichtigt, wenn
• CFs registriert oder abgemeldet wurden (hinzufügen zur oder entfernen aus der Liste),
• CFs als on- oder offline markiert wurden (entsprechenden Listeneintrag ausgrauen oder nicht),
• CFs ersetzt wurden (entsprechenden Listeneintrag ersetzen) oder
• eine Component in einer anderen View selektiert wurde (setzen des
Fokus auf die zugehörige CF).
Lokalisierung
Auch die Darstellung der CFs findet lokalisiert statt. Da sich das Angebot der CFs ändern kann, werden die Lokalisierungen als eigenständige
Fragment-Bundles realisiert. Ein Fragment-Bundle ist ein Bundle, dass als
KAPITEL 6. UMSETZUNG
65
Abbildung 6.8: Die verfügbaren CFs werden in einer Liste dargestellt. Ein
Doppelklick auf einen der Einträge erzeugt eine entsprechende ComponentInstanz. Klickt man auf einen Listeneintrag rechts, werden registrierte
ComponentFactorySelectionListeners darüber informiert.
Abbildung 6.9: Ein Host-Bundle (links oben) wird von einem FragmentBundle (links unten) erweitert. Danach sieht das Host-Bundle virtuell so aus,
wie rechts dargestellt.
Ergänzung zu einem anderen, bereits installierten, dient, das dann als HostBundle bezeichnet wird. Im Grunde wird das von der JAR-Datei repräsentierte Dateisystem des Host-Bundles mit dem des Fragment-Bundle verschmolzen (s. Abb. 6.9).
Wird eine neue CF im OSGi-Framework registriert, zu der es noch keine
Übersetzung gibt, so kann dieser Missstand durch Erweitern der SprachDatenbanken in den Fragment-Bundles nachgeholt werden. Änderungen im
GUI würden jedoch erst nach einer Auffrischung des Component-FactoriesBundles selbst ersichtlich werden. Der Vorteil bei dieser Vorgehensweise liegt
darin, dass es sehr einfach ist, zusätzliche Sprachen einzubinden. Das gelingt
durch das Einbinden weiterer Fragment-Bundles mit der entsprechenden
Lokalisierung.
KAPITEL 6. UMSETZUNG
66
Abbildung 6.10: Components werden als graue Blöcke dargestellt, Programmfluss-Ports sind weiße Rechtecke, Daten-Ports weiße Dreiecke, jeweils
schwarz umrandet. Die Links werden als Linien gezeichnet.
Der Grund, warum bei diesem Bundle auf Fragment-Bundles gesetzt
wird, beim GUI-Basis-Bundle aber nicht, liegt darin, dass beim GUI-BasisBundle die Übersetzung für die Sprachen Deutsch und Englisch komplett
umsetzbar ist, da sich die Elemente nicht dynamisch ändern. Sollten neue
Elemente in das GUI aufgenommen werden, muss das Bundle ohnehin neu
kompiliert werden und entsprechende Ergänzungen der Sprach-Datenbanken
könnten zu diesem Zeitpunkt eingefügt werden. Beim Component-FactoriesBundle können aber laufend neue Elemente zur Anzeige gebracht werden,
weshalb eine externe Sprach-Datenbank sinnvoller ist. Neue Sprachen können beim GUI-Basis-Bundle jedoch ebenfalls über Fragment-Bundles hinzugefügt werden.
6.2.3
Components und Links
Java-Package: net.bebedizo.torem.gui.componentlink.standard
Das Component-Link-Bundle realisiert die View zum Anzeigen der erstellten
Components und Links und ermöglicht das Hinzufügen, Löschen und Manipulieren von Links, sowie das Löschen von Components. Abb. 6.10 zeigt,
wie die Elemente in dieser View angezeigt werden.
Components
Da sich das Bundle als ComponentLinkVisualizer registriert hat, bekommt es
vom GUI-Basis-Bundle mitgeteilt, wenn Components erstellt oder gelöscht
werden und kann diese zur Anzeige bringen oder auch wieder löschen. Die
Darstellung der Components orientiert sich stark an den Visualisierungen
der Überlegungen, die in Abs. 4.1.1 angestellt wurden. Eine Component
KAPITEL 6. UMSETZUNG
67
Abbildung 6.11: Die Speicher-Component zeigt den gespeicherten Wert
an, sofern dieser ungleich null ist.
wird als graues Rechteck dargestellt, das auf der linken Seite die InputPorts und auf der rechten Seite die Output-Ports präsentiert. In der Mitte
des Rechtecks wird der Name der Component dargestellt. Daten-Ports werden als Dreiecke, Programmfluss-Ports als Rechtecke visualisiert. Der Benutzer kann die Components beliebig durch Draggen (Klicken und Ziehen)
mit der Maus positionieren. Ändert sich die Position einer Component, wird
der Position Manager darüber informiert. Umgekehrt reagiert die Visualisierung auf Positionsänderungen von Components, die z. B. von anderen Views
verursacht wurden.
Sobald sich die Maus über eine Component bewegt, werden alle registrierten ComponentSelectionListener darüber informiert. Ein Rechtsklick
auf eine Component lässt ein Aufklappmenü (engl. Popup Menu) erscheinen, das einen Eintrag zum Löschen der Component anbietet. Wählt man
diesen Eintrag aus, wird die Methode deleteComponent des CM aufgerufen.
Umgekehrt reagiert die View – nachdem sie im OSGi-Framework als
ComponentFactorySelectionListener registriert ist – darauf, wenn in einer
anderen View eine CF selektiert wurde. Tritt so ein Fall ein, werden alle
Components, die von dieser CF erzeugt wurden, für zwei Sekunden rot hinterlegt.
Diese Component-Link-View unterstützt außerdem die CF-Eigenschaft
torem.cf.isHandlingValue. Das bedeutet, das Components einer CF, die
diese Eigenschaft definiert hat, eine zusätzliche Information darstellen können. Als Wert der Eigenschaft muss die ID eines Ports angeben werden.
Ändert sich der Wert des Ports mit der gegebenen ID, wird dieser Wert in
der Component-Visualisierung dargestellt, wie Abb. 6.11 verdeutlichen soll.
Ports
Von der Visualisierung her sind Ports an die Components gebunden. Ändert
sich die Position einer Component, bewegen sich alle dazugehörigen Ports
mit. Der Name der Ports wird als Tooltip angezeigt und wird sichtbar, sobald
die Maus über einen Port bewegt wird. Bei Daten-Ports werden zusätzlich
der aktuelle Wert, der einem Port zugewiesen ist, sowie der Datentyp des
Ports, in den Tooltip integriert (s. Abb. 6.12).
Um Abseits von Links den Ports Werte zuweisen zu können oder Programmfluss-Ports zu aktivieren, genügt ein Doppelklick auf den gewünschten
Port. Ist es ein Programmfluss-Port, erscheint eine Schaltfläche (engl. Button) mit dem Titel Ausführen“ (s. Abb. 6.13). Durch Drücken der Escape”
KAPITEL 6. UMSETZUNG
68
Abbildung 6.12: Die Visualisierung des Port-Zustandes wird über einen
Tooltip gelöst. Der Name des Ports wird zusammen mit dem Datentyp und
dem aktuellen Wert dargestellt.
Abbildung 6.13: Mit einem Klick auf den Button wird der dahinterliegende
Port aktiviert.
Abbildung 6.14: Das Textfeld zum Setzen des Wertes eines Ports.
Taste verschwindet der Button, ohne eine Aktion auszuführen. Betätigt man
den Button aber, so wird die Methode setPortValue des CM mit dem Wert
null aufgerufen. Handelt es sich bei dem Port jedoch um einen Daten-Port,
erscheint nach dem Doppelklick ein Textfeld, in das ein Wert eingegeben
werden kann (s. Abb. 6.14). Auch diese Aktion kann durch Drücken der
Escape-Taste abgebrochen werden. Ist bereits ein Wert für den Port definiert, wird dieser Wert als Voreinstellung übernommen. Der eingegebene
String wird, entsprechend dem Datentyp des Ports, umgewandelt und ebenfalls über die Methode setPortValue dem CM übergeben. Die Umwandlung
wird mit Hilfe der Klasse ConversionHelper, die im Component-Bundle implementiert wird, durchgeführt.
Über Port-Wertänderungen wird dieses Bundle vom GUI-Basis-Bundle
informiert. Ein solches Ereignis führt dazu, dass der Tooltip der zugehörigen
Port-Visualisierung aktualisiert wird.
Links
Die Darstellung der Links erfolgt durch Zeichnen von Linien, die die betroffenen Ports miteinander verbinden. Ändert sich die Position der zu verbindenden Ports, wird auch die Link-Visualisierung dementsprechend aktuali-
KAPITEL 6. UMSETZUNG
69
Abbildung 6.15: Der Textbereich zeigt den Quellcode des dem gelb markierten Link zugeordneten Converters an.
siert. Je nach Zustand des Links wird dieser mit unterschiedlichen Farben
visualisiert:
• Schwarz: Programmfluss-Links sowie Daten-Links, die keiner Konvertierung bedürfen, werden schwarz gezeichnet.
• Grün: Wird ein Programmfluss-Link aktiviert, oder transportiert ein
Datenfluss-Link ein Datum, wird dies der Visualisierung über das GUIBasis-Bundle mitgeteilt, welche daraufhin den Link für 500 Millisekunden grün zeichnet. So kann der Benutzer sehen, wann ein Link etwas
zu tun hat.
• Blau: Enthält ein Daten-Link einen Converter, so wird er blau dargestellt. Zusätzlich wird der Quellcode der convert-Methode in Form einer javax.swing.JTextArea (dt. Textbereich) angezeigt, wenn die Maus
über einen Link positioniert wird (s. Abb. 6.15).
• Rot: Ungültige Daten-Links – das sind jene, deren Port-Datentypen
zueinander inkompatibel sind und denen noch kein geeigneter Converter zugewiesen wurde – werden rot dargestellt.
• Gelb: Wird die Maus über einen Link bewegt, wird dieser gelb markiert.
Um einen Link zu löschen, genügt ein Rechtsklick, wenn sich die Maus
über dem Link befindet. Aus dem erscheinenden Popup-Menü kann der Eintrag Löschen“ verwendet werden, um die Methode removeLink des LM auf”
zurufen. Das Zuweisen eines Converters zu einem Link funktioniert ebenfalls
über das Popup-Menü und den Eintrag Bearbeiten“, der allerdings nur bei
”
Daten-Links zur Verfügung steht. Die Auswahl dieses Eintrags führt dazu,
dass alle registrierten ConverterSelectionListener darüber informiert werden, dass ein Link bearbeitet werden soll.
Diese View verwendet die selbe Methode der Lokalisierung wie die Component-Factories-View in Abs. 6.2.2: Die Sprach-Datenbank-Dateien werden
über Fragment-Bundles definiert.
KAPITEL 6. UMSETZUNG
6.2.4
70
Converters
Java-Package: net.bebedizo.torem.gui.converter.standard
Die Visualisierung der Converters ist die erste, die in der Kategorie All
”
Purpose Visualizers“ und damit im rechten oberen Bereich des JFrames zur
Anzeige gebracht wird. Vom GUI-Basis-Bundle wird sie informiert, sobald
Converters erstellt oder gelöscht werden.
Die Darstellung ist in vier Bereiche unterteilt: Eine Titelleiste oben, in
der der Name für ein Converter-Script vergeben werden kann, eine Liste
links, die alle verfügbaren Converters auflistet und ein Textbereich rechts,
der das Schreiben eigener Converters erlaubt. In diesem Textbereich kann
auch der Quelltext der convert-Methode des in der Liste ausgewählten
Converters angezeigt werden. Unten befinden sich noch Buttons, die beim
Betätigen die Kommunikation zum Converter Manager übernehmen.
Die Converter-View unterscheidet zwischen zwei Stati, in denen sie sich
befinden kann. Im Link-gebundenen Status betreffen Converter-Änderungen
einen bestimmten Link, im Link-ungebundenen Status können Converter
ganz allgemein manipuliert werden, ohne die den Links zugeteilten Converters zu verändern.
Link-ungebundener Status
In diesem Status werden im unteren Bereich drei Buttons angezeigt, die
dem Benutzer die Möglichkeit geben, Befehle an den Converter Manager
abzusetzen:
• Neu: Dieser Button dient zum Erzeugen eines neuen Converters. Das
Betätigen dieses Buttons öffnet einen Dialog, in dem der Benutzer
aufgefordert wird, Ausgangs- und Ziel-Datentyp festzulegen. Danach
erscheint im Textbereich ein Quellcode-Fragment, dass als Orientierungshilfe dienen soll und, sofern das möglich ist, die Konvertierung
des Ausgangs-Datentyps in einen primitiven Datentyp vornimmt, um
Berechnungen durchführen zu können. Soll bspw. eine Konvertierung
von Boolean zu Integer vorgenommen werden, wird der Java-Quellcode boolean b = (Boolean)value; in das Textfeld geschrieben. Der
Benutzer kann nun seinen Konvertierungs-Algorithmus in Java-Syntax
angeben (s. Abb. 6.16).
• Speichern: Mit diesem Button wird der im Textbereich definierte
Quellcode dem Converter Manager gemeinsam mit den ausgewählten
Datentypen sowie dem Inhalt des oberen Textfelds als Name übergeben
(s. Abs. 6.1.3). Zunächst wird geprüft, ob der Quellcode kompilierbar
ist. Ist er das nicht, wird dem Benutzer die Zeile eines Syntax-Fehlers
angegeben und der Hintergrund des Textbereiches blinkt kurz rot auf.
KAPITEL 6. UMSETZUNG
71
Abbildung 6.16: Die Converter-View im Link-ungebundenen Status. Links
ist die Liste der verfügbaren Converters, rechts das derzeit entwickelte Script
und oben kann ein Name für das Script gewählt werden. Unten befinden sich
die Buttons zum Absetzen der Steuerbefehle.
Ist der Quelltext kompilierbar, wird er der Liste der verfügbaren Converters über ein vom Converter Manager generiertes ConverterEvent
hinzugefügt.
• Löschen: Über diesen Button wird der aktuell in der Liste ausgewählte Converter vom Converter Manager gelöscht und steht nicht
länger zur Verfügung. Sollten bereits Links diesen Converter als ih”
ren“ Converter benutzen, so sind sie vom Löschvorgang nicht betroffen.
Bei diesen Links bleibt der Converter erhalten.
Link-gebundener Status
Nachdem das Bundle als ConverterSelectionListener im OSGi-Framework
registriert ist, wird gelegentlich die Methode converterSelected aufgerufen.
Das ist z. B. der Fall, wenn in der Component-Link-View der Eintrag Bear”
beiten“ aus dem Popoup-Menü eines Daten-Links ausgewählt wird. Wird
diese Methode aufgerufen, so wechselt die Converter-View in den Linkgebundenen Status. Visuell macht sich das dadurch bemerkbar, dass die
View rot umrandet wird, und dass nun vier Buttons zur Verfügung stehen,
wie in Abb. 6.17 dargestellt. Aktionen die in diesem Status durchgeführt
werden, betreffen den Link, der hinter der ID steckt, die in der Methode
converterSelected übergeben wurde.
Nachdem der Converter in Bezug zu einem Link steht, sind Ausgangsund Ziel-Datentyp bereits vorgegeben. Um dem Benutzer die Zuweisung
eines existierenden Converters zu vereinfachen, wird die Liste der Converters
KAPITEL 6. UMSETZUNG
72
Abbildung 6.17: Die Converter-View, diesmal im Link-gebundenen Status. Deutlich sichtbar ist die rote Umrandung, mit der dieser Status markiert wird. Die Liste der Converters ist auf einen einzigen passenden Eintrag
geschrumpft.
auf jene beschränkt, die kompatibel zu den benötigten Datentypen sind.
Alle anderen Converters werden ausgeblendet. Der Benutzer hat nun die
Möglichkeit, einen Converter aus der Liste auszuwählen, oder einen eigenen
zu definieren, wobei die selben Regeln wie zuvor erklärt gelten.
Die vier Buttons haben folgende Bedeutung:
• Neu: Dieser Button hat die selbe Funktionalität wie der Neu-Button
im ungebundenen Status, jedoch mit dem Unterschied, dass der Benutzer die Datentypen nicht festlegen muss, da diese ja durch die beiden
gekoppelten Ports des Links definiert sind.
• Übernehmen: Übernehmen sorgt dafür, dass der durch den im Textbereich vorhandenen Quelltext definierte Converter dem Link zugeordnet wird. Entspricht das Script einem bereits existierenden Converter,
so wird eine neue Instanz dessen angelegt und dem Link zugeordnet.
Existiert kein Converter mit dem dargestellten Quelltext, so wird nach
dem selben Prinzip wie beim Speichern eines ungebundenen Scripts
vorgegangen. Ist die Kompilation erfolgreich, wird eine Instanz des
neu generierten Converters dem Link zugeordnet.
• Löschen: Mit dem Löschen-Button wird dem Link der Wert null
als Converter gesetzt. Das ist gleichbedeutend mit dem Löschen des
Converters aus dem Link.
• Abbrechen: Dieser Button beendet den Link-gebundenen Status zugunsten des Link-ungebundenen. Die rote Umrandung verschwindet,
und es sind wieder die drei Buttons, die zuvor beschrieben wurden, zu
sehen.
KAPITEL 6. UMSETZUNG
6.3
73
Erweiterungen
Die in diesem Abschnitt beschriebenen Bundles stellen nützliche Erweiterungen in Form von Zusatz-Bundles dar. Teilweise werden CFs und Converters (also Erweiterungen in der Model-Schicht) dem OSGi-Framework
hinzugefügt, teilweise werden neue View-Implementierungen definiert.
6.3.1
Standard Ingredients
Java-Package: net.bebedizo.torem.standardingredients
Die Standard Ingredients sind einerseits eine Sammlung an Component Factories, die Components für wichtige Grundfunktionen zur Verfügung stellen
(If-Anweisungen, Schleifen, Arrays, usw.) und andererseits eine Sammlung
vieler Converters, die Standard-Konvertierungen zwischen den primitiven
Datentypen und String anbieten. Ein eigenes GUI-Bundle (s. unten) sorgt
für die geeignete Darstellung der CFs.
Component Factories
Java-Package: net.bebedizo.torem.standardingredients.component
Für folgende Components werden CFs definiert (in Klammern der Name
in der deutschen Lokalisierung) – einen visuellen Index bietet Abb. 6.18:
• Addition (Addition): Addiert zwei double-Werte miteinander.
• Array (Array): Repräsentiert ein String-Array. Die Definition des Arrays erfolgt über eine XML-Zeichenkette im Format:
<tl><element value="Wert1"/>...<element value="Wert2"/></tl>.
• ChangeDetection (Änderungs-Detektion): Nimmt nacheinander Werte
auf und liefert true oder false, je nachdem ob sich zwei aufeinanderfolgende Werte unterscheiden oder nicht (wird über die equals-Methode
entschieden).
• Delay (Verzögerung): Verzögert den Programmfluss um die angegebene Zahl von Millisekunden. Definiert torem.cf.isHandlingValue zur
Anzeige der Millisekunden.
• Equality (Gleichheit): Testet die beiden Eingangswerte auf Gleichheit mittels der equals-Methode.
• For (For-Schleife): Repräsentiert eine for-Schleife. Es können der
Startwert, der Endwert und die Schrittweite der Laufvariablen als
Ganzzahl-Werte angegeben werden. Der Schleife-Aus-POP dient dem
Definieren eines Programmflusses, der innerhalb eines Schleifendurchlaufes ausgeführt werden soll und sollte im Schleife-Ein-PIP münden.
KAPITEL 6. UMSETZUNG
74
Ist die definierte Anzahl an Schleifendurchläufen durchgeführt worden,
wird der Beendet-POP aktiviert.
• If (Wenn): Diese Component stellt eine if-Anweisung dar. Wenn der
Eingangswert true ist, wird der obere POP aktiviert, ansonsten der
untere.
• Inversion (Umkehrung): Invertiert den (boolschen) Eingangswert.
• Logging (Logging): Dient der Protokollierung eines Wertes. Der Wert
wird mittels der toString-Methode in einen String konvertiert. Diese
Component definiert keine Programmfluss-Ports – jeder Wert, der den
DIP erreicht, wird protokolliert.
• RepeatedInvocation (Wiederholter Aufruf): Geeignet als Quelle eines Programmflusses. Nach der Aktivierung des Start-PIPs wird der
POP alle Pause Millisekunden aktiviert, bis der Stop-PIP zum Stoppen
verwendet wird. Definiert die Eigenschaft torem.cf.isHandlingValue
für die Anzeige der Millisekunden, die zwischen den POP-Aktivierungen gewartet wird.
• Storage (Speicher): Speichert einen Wert vom Typ Object zwischen.
Definiert die torem.cf.isHandlingValue-Eigenschaft für den zwischengespeicherten Wert.
• Switch (Auswahl): Simuliert eine switch-Anweisung, die auf IntegerZahlen für die Fallunterscheidungen basiert. Die Anzahl der Fälle ist
derzeit mit sechs begrenzt – eine wünschenswerte Weiterentwicklung
wäre es, die Anzahl beim Erstellen der Component bestimmen zu
können. Zusätzlich gibt es noch den Fall, der eintritt, wenn keiner
der sechs zuvor getesteten Fälle eintritt. Die Output-Ports sind alle
POPs, da es die Aufgabe der switch-Anweisung ist, den Programmfluss zu teilen.
• While (While-Schleife): Eine while-Schleife, die so lange läuft, bis
der Eingangsparameter auf false gesetzt wird. Der Schleife-Aus-POP
sollte nachdem die notwendigen Components dazwischengeschalten
wurden, im Betreten-PIP münden, um die Schleife zu definieren.
Sämtliche Components leiten sich von der Klasse AbstractComponent ab,
die im Component-Bundle definiert wird. Um diese Components in Torem
nutzen zu können, müssen CFs registriert werden, die für die Erzeugung der
Components sorgen. Dazu dient in diesem Bundle jeweils eine Instanz der
Klasse SampleComponentFactory, die von ComponentFactoryPrototype abgeleitet ist. Bei den CFs dieses Bundles wird die Eigenschaft torem.cf.type
auf Default gesetzt, was von der zugehörigen View genutzt wird, um diese
CFs zu erkennen.
Stellvertretend für die anderen Components wird in Anhang A die Entwicklung der If-Component näher erläutert.
KAPITEL 6. UMSETZUNG
75
Abbildung 6.18: Die 13 Components der Standard Ingredients.
Converters
Java-Package: net.bebedizo.torem.standardingredients.converter
Insgesamt werden 65 Converters implementiert und im OSGi-Framework
registriert. Diese dienen als Standard-Implementierungen für die Konvertierungen zwischen den primitiven Datentypen und Strings. Auf eine Auflistung der Converters wird an dieser Stelle aufgrund der großen Anzahl
verzichtet. Da der Quelltext der convert-Methoden jeweils nur eine Zeile
lang ist hält sich die Komplexität der Converters in Grenzen.
View
Java-Package: net.bebedizo.torem.gui.componentfactory.standard
Diese View gleicht der Component-Factories-View aus Abs. 6.2.2, bis auf
die Anzahl der dargestellten CFs. Es werden nur jene CFs dargestellt, die
als Wert der torem.cf.type-Eigenschaft Default definiert haben. Im Gegensatz dazu zeigt die Component-Factories-View alle verfügbaren CFs an.
Diese View verwendet ebenfalls Fragment-Bundles (s. Abs. 6.2.2), um
die Mehrsprachigkeit umzusetzen.
KAPITEL 6. UMSETZUNG
6.3.2
76
UPnP
Die Einbindung des UPnP-Protokolls erfolgt über zwei Bundles, wobei eines
das Definieren und Registrieren der CFs übernimmt (Model) und das andere
für eine übersichtliche Auswahlliste der UPnP-CFs sorgt (View).
Component Factories
Java-Package: net.bebedizo.osgi.service.upnp.controlpoint
In [23] wird die Einbindung von UPnP-Geräten ins OSGi-Framework spezifiziert. Für diese Spezifikation gibt es eine Open Source Implementierung,
die unter der LGPL lizensiert ist: der Domoware UPnP Base Driver7 . Er
verwendet die Java-Variante von Cyberlink als UPnP-Bibliothek.
Dieses Bundle repräsentiert einen UPnP Control Point, der vom UPnP
Base Driver über entdeckte sowie sich abmeldende UPnP-Geräte informiert
wird. Ein Geräte Manager (engl. Device Manager) sorgt für das Einbinden
der Geräte in Torem, indem für jede Aktion und jede Statusvariable eines
Gerätes eine CF erstellt und im Framework registriert wird. Der Ablauf des
Device Managers, wenn ein UPnP-Gerät registriert wird, sieht folgendermaßen aus:
WIEDERHOLE für jeden UPnP - Dienst innerhalb des Gerätes :
WIEDERHOLE für jede UPnP - Aktion innerhalb des
aktuellen Dienstes :
erstelle eine Aktions - CF
registriere die Aktions - CF im OSGi - Framework
WIEDERHOLE_ENDE
WIEDERHOLE für jede UPnP - Statusvariable ( SV ) innerhalb
des aktuellen Dienstes :
WENN die SV Statusänderungen an Abonnenten
verschickt DANN
erstelle eine SV - CF
registriere die SV - CF als Abonnent bei der SV
registriere die SV - CF im OSGi - Framework
WENN_ENDE
WIEDERHOLE_ENDE
WIEDERHOLE_ENDE
Meldet sich ein Gerät ab, wird folgender Algorithmus angewandt:
WIEDERHOLE für jede Aktions - CF die unter diesem Gerät
registriert wurde :
melde diese Aktions - CF vom OSGi - Framework ab
WIEDERHOLE_ENDE
WIEDERHOLE für jede SV - CF die unter diesem Gerät
registriert wurde :
7
http://domoware.isti.cnr.it/documentation.html
KAPITEL 6. UMSETZUNG
77
melde diese SV - CF vom OSGi - Framework ab
kündige das Abonnement der SV - CF bei der SV
WIEDERHOLE_ENDE
Um der Gleichheits-Ähnlichkeits-Problematik beizukommen, werden folgende Eigenschaften von UPnP-Geräten als Similarites (wenn diese Werte
übereinstimmen, gelten zwei CFs als ähnlich) in den CFs gespeichert:
• Die ID des Dienstes dem die CF angehört und
• der Gerätetyp des zugehörigen Gerätes.
Folgende Eigenschaften werden als Equalities (wenn diese Werte und die
Similarities übereinstimmen, gelten zwei CFs als gleich) gespeichert:
• Die ID,
• der Friendly Name“ (ein kurzer menschenlesbarer String zur Beschrei”
bung des Gerätes),
• der Modellname,
• die Seriennummer,
• die Modellnummer und
• die Modellbeschreibung des Gerätes.
UPnP-Aktions-Components werden gebildet, indem jeder Eingangsparameter der Aktion in einen DIP und jeder Ausgangsparameter in einen
DOP abgebildet wird. Wird einem der DIPs ein Wert zugewiesen, so wird
dieser in einem java.util.Dictionary-Objekt in der Component gespeichert,
das später zum Ausführen der Aktion verwendet wird. Zusätzlich wird ein
PIP definiert, dessen Aktivierung intern so umgesetzt wird, dass die invokeMethode der UPnP-Aktion aufgerufen wird – mit dem zuvor angesprochenen
Dictionary-Objekt als Parameter. Dieser Methodenaufruf wird vom UPnP
Base Driver mittels der Cyberlink-Bibliothek in einen UPnP-kompatiblen
HTTP-Request umgewandelt und an das UPnP-Gerät gesandt. Die Antwort des UPnP-Gerätes wird ebenfalls als Dictionary-Objekt an die UPnPAktions-Component zurückgeliefert, wo dessen Inhalt an die DOPs weitergegeben wird. Abschließend wird der ebenfalls erstellte POP aktiviert, um
den Programmfluss weiterlaufen zu lassen. Abb. 6.19 zeigt den schematischen Aufbau einer UPnP-Aktions-Component.
UPnP-Statusvariablen-Components definieren einen DOP und einen
POP. Wird die zugehörige CF über eine Statusänderung der entsprechenden
Statusvariable informiert, leitet die CF dieses Ereignis an alle instanzierten Components weiter. Innerhalb der Component wird zunächst dem DOP
KAPITEL 6. UMSETZUNG
78
Abbildung 6.19: Die UPnP-Aktions-Component setzt die Eingansparameter zu einer SOAP-Nachricht zusammen und schickt diese an das UPnPGerät. Dessen SOAP-Antwort wird anschließend geparst und an die DOPs
weitergeleitet, bevor der POP aktiviert wird.
Abbildung 6.20: Das vom UPnP-Gerät geschickte Ereignis im SOAPFormat wird geparst und der Wert des Ereignisses dem DOP übermittelt.
Danach wird der POP aktiviert.
der neue Wert zugewiesen und anschließend der POP aktiviert. Die UPnPStatusvariablen-Components sind reine Ereignis-Components und besitzen
keine Input-Ports. Der interne Aufbau einer UPnP-Statusvariablen-Component sieht wie in Abb. 6.20 gezeigt aus.
View
Java-Package: net.bebedizo.torem.gui.componentfactory.upnp
Um die verfügbaren UPnP-Components – sowohl Aktionen als auch Statusvariablen – übersichtlich anzeigen zu können, wird eine Baumstruktur als
Darstellungsform gewählt, da diese dem hierarchischen Aufbau eines UPnPGerätes entspricht. Jedes UPnP-Gerät besteht aus drei Ebenen: In Ebene 0
befindet sich das Gerät selbst, Ebene 1 stellt die Dienste innerhab eines
KAPITEL 6. UMSETZUNG
79
Abbildung 6.21: Die UPnP-Geräte werden als Wurzel-Knoten untereinander angeordnet und sind blau eingefärbt. Die untergeordneten UPnP-Dienste
sind rot und eingerückt visualisiert und beinhalten UPnP-Aktionen (grau)
und UPnP-Statusvariablen (grün). Die weißen Dreiecke dienen dem Falten der Hierarchie-Ebenen, um die Übersichtlichkeit zu erhöhen. Der Dienst
SwitchPower“ ist bspw. gefalten.
”
Gerätes dar und in Ebene 3 folgen die Aktionen und Statusvariablen der
Dienste (s. Abb. 6.21).
Die entdeckten UPnP-Geräte werden untereinander gelistet und bieten
Schaltflächen zum Minimieren der einzelnen Hierarchie-Ebenen an, um die
Übersichtlichkeit zu gewährleisten. Ein Doppelklick auf eine Aktion oder
Statusvariable sorgt für die Instanzierung einer entsprechenden Component
über den CM. Rechtsklicken auf eine CF schickt ein Ereignis an alle registrierten ComponentFactorySelectionListeners.
Werden CFs als offline markiert, werden sie mit grauem Hintergrund
dargestellt. Dieses Ausgrauen“ zieht sich bis in die oberste Hierarchieebene
”
(s. Abb. 6.22). Sobald die CFs wieder online markiert werden, bekommt der
Baum seine Farbe zurück.
Nachdem diese View als ComponentSelectionListener registriert ist, erhält sie Benachrichtigungen, wenn eine Component selektiert wurde. In
so einem Fall wird die zugehörige CF sowie die übergeordneten Elemente
(Dienst und Gerät) für 1000 Millisekunden rot eingefärbt (s. Abb. 6.23).
Das ermöglicht das leichtere Zuordnen von Components zu CFs (praktisch
für den Fall, dass zwei UPnP-Aktionen den gleich Namen haben, aber von
unterschiedlichen UPnP-Geräten zur Verfügung gestellt werden.
6.3.3
Remote GUI
Das GUI soll nicht nur im selben OSGi-Framework wie die Kern-Bundles
lauffähig sein, sondern auch auf einem entfernten Host. Damit ist es mög-
KAPITEL 6. UMSETZUNG
80
Abbildung 6.22: Das UPnP-Geräte Light (MC-NB19)“ steht nicht länger
”
zur Verfügung. Die zugehörigen UPnP-CFs, die bereits Components instanziert haben, werden grau dargestellt.
Abbildung 6.23: Wird eine Component markiert, werden die zugehörigen
UPnP-CFs rot eingefärbt. Somit kann schnell erkannt werden, welche Component welchem UPnP-Gerät zuzuordnen ist.
lich, einen Server, der sich um die Umsetzung des definierten Mappings
kümmert, auf einem Host laufen zu haben, zu dem sich eine oder mehrere
GUI-Applikationen verbinden, die auf anderen Host ausgeführt werden, um
das Mapping zu modifizieren. Die folgenden drei Bundles beschreiben die
Implementierung einer Server-Client-Architektur, die es erlaubt, die zuvor
beschriebenen View-Bundles ohne Änderungen sowohl lokal als auch entfernt
laufend zu verwenden.
KAPITEL 6. UMSETZUNG
81
Abbildung 6.24: Instanzdiagramm des Netzwerk-Bundles.
Netzwerk-Infrastruktur
Java-Package: net.bebedizo.util.connection
Dieses Bundle implementiert Klassen die die Netzwerk-Kommunikation über
TCP8 /IP ermöglichen. Dazu zählt erstens ein Server, der auf einem Port
horcht und hereinkommende Verbindungen annimmt, zweitens eine Connection-Klasse, die die Kommunikation zwischen Server und Client übernimmt und drittens eine Nachrichten-Klasse, die die zu übermittelnden Nachrichten spezifiziert.
Kommunikation Der Server wird mit Hilfe des java.net.ServerSocket
in der Klasse TcpConnectionListener implementiert, und legt für jede angenommene Verbindung ein Objekt der java.net.Socket-basierten Kommunikationsklasse TcpObjectConnection an, das jeweils für die Netzwerkkommunikation in einem isolierten Thread läuft. Jede der erstellten Connections leitet eingehende Nachrichten, die den Beginn einer Kommunikation
darstellen, an den ihr zugewiesenen NotificationProcessor weiter. Nachrichten, die Antworten auf eine zuvor gestellte Anfrage sind, werden an den
ResponseHandler weitergeleitet (s. Abb. 6.24).
Nachrichten Die Nachrichten werden in Form von serialisierten Objekten
zwischen Server und Client ausgetauscht. Ein solches Nachrichten-Objekt
besteht aus einer fortlaufenden ID, die dazu dient, Anfragen und Antworten
über das Netzwerk zuordnen zu können, einer Integer-Zahl, die den Typ der
Nachricht definiert und dem Objekt, das übermittelt werden soll. Die Klasse
net.bebedizo.util.connection.message.GenericMessage implementiert die8
Transport Control Protocol. Details dazu finden sich in [13]
KAPITEL 6. UMSETZUNG
82
ses Nachrichten-Objekt für Torem. In dieser Klasse sind auch alle 33 für
Torem notwendigen Nachrichten-Typen definiert.
Server
Java-Package: net.bebedizo.torem.network.server
Das Server-Bundle startet einen TcpConnectionListener, der auf eingehende
Verbindungen wartet und entsprechend der oben gezeigten Vorgangsweise
für eingehende Verbindungen jeweils eine TcpObjectConnection erzeugt. Als
NotificationProcessor dient die Klasse AllEventListener, in der die gesamte Logik des Server-Bundles implementiert ist.
Um die Anfragen von Clients durchführen zu können, hält sich der
AllEventListener Referenzen zu den vier Managern der Kern-Bundles, die er
über das Dienst-System des OSGi-Frameworks erhält. Ist mit einer Anfrage
das Ausführen einer Manager-Methode verbunden, die einen Rückgabewert
liefert, so wird der Rückgabewert als Nachricht an den Client zurück-übermittelt. Wird jedoch eine Methode ohne Rückgabewert aufgerufen, erhält
der Client darüber keine Benachrichtigung.
Um die Clients über Model-Änderungen auf dem Laufenden zu halten, registriert sich der AllEventListener als Listener für alle in den KernBundles definierten Ereignisse. Tritt ein Ereignis auf, teilt er dies allen verbundenen Clients mit. Für das Server-seitige OSGi-Framework simuliert der
Server damit im Grunde eine View-Implementierung, die über jedes Ereignis
informiert werden möchte.
Client
Java-Package: net.bebedizo.torem.network.client
Der Client verbindet sich über IP und Port zu einem Server und kann diesem die in der GenericMessage-Klasse definierten Nachrichten schicken, die
auf der Server-Seite in Methoden-Aufrufe von Manager-Klassen umgesetzt
werden. Die Logik des Clients konzentriert sich in einer einzigen Klasse,
dem AllManagersProvider. Diese vereint alle vier Manager der Kern-Bundles
und registriert sich dementsprechend im OSGi-Framework. Anderen Bundles im Client-seitigen OSGi-Framework wird das Gefühl vermittelt, direkt
mit den Managern zu kommunizieren. Wird eine Manager-Methode des
AllManagersProvider aufgerufen, wandelt dieser die damit verbundene Anfrage in eine Nachricht um und sendet diese an den Server. Definiert die
Methode einen Rückgabewert, wartet der AllManagersProvider auf die entsprechende Antwort vom Server und gibt den darin enthaltenen Wert zurück,
ansonsten wird die Methode sofort nach dem Absetzen der Nachricht beendet.
KAPITEL 6. UMSETZUNG
83
Abbildung 6.25: Der Nachrichtenfluss in der Server-Client-Architektur.
Ereignis-Nachrichten, die vom Server an die Clients versandt werden,
leitet der AllManagersProvider an die im Client-seitigen OSGi-Framework
registrierten Event Listeners weiter. Werden mehrere GUIs gleichzeitig betrieben, so wird die Component-Link-View aufgrund des Position Managers
auch über Netzwerkgrenzen hinweg konsistent gehalten.
Abb. 6.25 zeigt den Nachrichtenfluss dieser Server-Client-Architektur.
Der hier gewählte Ansatz ermöglicht auch einen Mischbetrieb, in dem es
sowohl ein lokales GUI am Server, als auch entfernte GUIs gibt.
6.4
Szenario
Abschließend soll ein kleines Szenario umgesetzt werden, um die Brauchbarkeit des entwickelten Prototyps im laufenden Betrieb zu testen. Eine
mit Drucksensoren ausgestattete Holzplatte soll dazu dienen, ein MedienAbspielgerät (engl. Media Player) zu steuern. Drückt man mit dem Finger
leicht auf einen der Drucksensoren, soll eine gewisse Funktion (das Abspielen
starten, stoppen, pausieren, ...) des Media Players ausgeführt werden. Abb.
6.26 zeigt den schematischen Aufbau dieser Installation.
Die Platte mit den Sensoren ist über TCP/IP ansprechbar, und so wurde
für das Auslesen der aktuellen Druckwerte ein UPnP-Gerät entwickelt, dass
unter anderem die UPnP-Aktion GetSensor anbietet, über welche die Werte
der Drucksensoren als String bereitgestellt werden. Intern kommuniziert das
UPnP-Gerät mit der Sensor-Platte über ein proprietäres Protokoll.
Der Media Player wurde mit dem Java Media Framework 9 (JMF) ebenfalls als UPnP-Gerät entwickelt und bietet entsprechende UPnP-Aktionen
für die an ihm durchführbaren Funktionen an.
Zur Umsetzung mit Torem wurden Components der Standard Ingredients (s. Abs. 6.3.1) mit den UPnP-Aktionen gekoppelt. Abb. 6.27 zeigt
9
http://java.sun.com/products/java-media/jmf/
KAPITEL 6. UMSETZUNG
84
Abbildung 6.26: Eine Platte mit neun Drucksensoren ist über TCP/IP ansprechbar – ein entsprechendes UPnP-Gerät wurde entwickelt, um die Kommunikation mit der Sensorplatte zu abstrahieren. Torem liest die SensorWerte aus, ordnet sie den UPnP-Aktionen des Media Players zu und führt
beim Drücken eines Sensors die zugehörige Aktion aus.
das entworfene Mapping in der Component-Link-View (s. Abs. 6.2.3): Die
UPnP-Aktion GetSensor wird alle 200 ms aufgerufen, und die zurückgegebenen Sensorwerte werden in einem Array gespeichert. Nun werden die ersten
sechs Einträge benutzt, um die sechs Funktionen des Media Players anzusteuern. Ein Drucksensor gilt als gedrückt“, wenn der Sensorwert unter
”
2000 fällt (im ungedrückten Zustand bewegen sich die Werte im Bereich
von 3500). Für jeden der Sensorwerte wird ein eigener Programmfluss definiert, der das Ansteuern der zugewiesenen UPnP-Aktion übernimmt. Da
die Pause-Funktion des Media Players zwischen Pause und Play wechselt,
je nachdem in welchem Zustand der Media Player gerade ist, wird mit ein
paar zusätzlichen Components sichergestellt, dass ein zu langes Drücken
des Pause-Drucksensors nicht mehrfach an den Media Player gesandt wird.
Stattdessen müssen zumindest 2500 Millisekunden vergehen, bis der Wert
des Drucksensors wieder beachtet wird. Die XML-Datei für dieses Szenario kann auf der CD unter dem Pfad /samples/sensorPlayer.xml eingesehen
werden.
KAPITEL 6. UMSETZUNG
Abbildung 6.27: Die Umsetzung des oben genannten Szenarios. Bis auf
die Bedingung, ab welchem Wert ein Sensor als gedrückt gilt, musste keine
Zeile Code selbst programmiert werden. Die Bedingung wurde mittels der
Converter-View erstellt un dem Daten-Link zwischen Array und Wenn
(rechts oben) zugewiesen.
85
Kapitel 7
Fazit
An dieser Stelle werden die Erfahrungen und Erkenntnisse, die im Laufe
dieser Arbeit gewonnen wurden, sowie Vorschläge zur Weiterentwicklung
angeführt.
7.1
Ergebnisse
Der entwickelte Prototyp, Torem, konnte bei der Implementierung eines einfachen Szenarios (s. Abs. 6.4) seine Brauchbarkeit unter Beweis stellen. In
kurzer Zeit wurden die Components und Links so angeordnet, dass sie die
gewünschte Funktionalität umsetzten. Wie bei anderen grafischen Programmierumgebungen, ist jedoch eine gewisse Einarbeitungszeit nicht von der
Hand zu weisen, die benötigt wird, um mit der Funktionsweise der Components zurechtzukommen.
Mit Torem konnte auch gezeigt werden, dass sich das OSGi-Framework
für die Entwicklung einer dynamischen Applikation hervorragend eignet,
und dass durch die Aufteilung der Programmlogik in mehrere Bundles eine
saubere Trennung der verschiedenen Logik-Bausteine gefördert wird.
Durch die Einbindung von UPnP eröffnet sich mit einem Schlag eine
große Palette an Geräten, die von Torem aus angesteuert werden können.
Das interessante an UPnP ist, dass es sich nicht um eine Java-spezifische
Technologie handelt, sondern dass damit ein Sprach-unabhängiges Protokoll
gewonnen werden konnte. Die Einbettung von UPnP dient in dieser Arbeit
als Beispiel für die Einbindung eines von Java nicht direkt unterstützten
Protokolls.
Es war eine durchaus fordernde Aufgabe, ein Model zu erarbeiten, dass
die Integration möglichst vieler verschiedener Technologien ermöglicht. Die
Entscheidung fiel zuguterletzt auf die Entwicklung eines sehr lockeren Komponenten-Begriffs, der jeder Komponenten-Implementierung sehr viel Freiraum lässt, was das Umgehen mit Port-Wertzuweisungen angeht. Es wäre
möglich, auf Programmfluss-Ports komplett zu verzichten und nur mit Da86
KAPITEL 7. FAZIT
87
ten-Kopplungen zu arbeiten. Die Unterscheidung zwischen Programm- und
Datenfluss erweist sich allerdings als praktisch, da so eine bessere Steuerung
der Komponenten-Zugriffe erreicht wird.
Der aktuelle Entwicklungsstand von Torem ist in einem zufriedenstellenden Stadium. Torem läuft zuverlässig auch über mehrere Tage hindurch
und könnte daher auch für längerfristige Installationen eingesetzt werden.
Dabei bietet sich der Server-Client-Betrieb an, in dem Clients nur dann gestartet werden, wenn Änderungen vorgenommen werden müssen, oder um
den aktuellen Status der Components und Links einzusehen. Der Server
läuft ohne graphische Oberfläche unauffällig im Hintergrund und erledigt
die Durchführung der Kopplungen.
7.2
Ausblick
Durch die Erweiterbarkeit von Torem ist es möglich, weitere Technologien
und Protokolle zu integrieren. Die Einbindung von Jini-fähigen Geräten
sollte bspw. recht einfach möglich sein, da Torem eine Java-basierte Applikation ist. Andere Protokolle, wie der European Installation Bus1 (EIB)
bedürfen evtl. eines höheren Aufwandes, eine Integration sollte dennoch
möglich sein: Die indirekte Einbindung von EIB-Geräten wurde durch einen
UPnP-EIB Treiber bereits ermöglicht, der die Geräte einer EIB-Installation
in das UPnP-Netzwerk exportiert. Die Nutzung über UPnP wäre also bereits möglich. Der UPnP-EIB-Treiber liegt als OSGi-Bundle auf der CD im
Verzeichnis /torem/source/net.bebedizo.osgi.service.upnp.eib/ bei.
Neben der Weiterentwicklung durch die Einbindung zusätzlicher Protokolle ist auch die Verbesserung des GUIs ein Thema. Alle von den Managern
der Kern-Bundles angebotenen Methoden lassen sich zwar nutzen, doch die
Benutzerfreundlichkeit ist teilweilse noch nicht zufriedenstellend hoch. Vor
allem die Darstellung von und die Interaktion mit den Components und
Links könnte Verbesserungen gut verkraften. Einerseits sollte die Gruppierung mehrerer Components in eine Super-Component ermöglicht werden
(wobei das auch Änderungen am Model und der Control mit sich ziehen
würde), um das Schaltbild übersichtlich gestalten zu können. Andererseits
wäre es von Vorteil die gekoppelten Ports nicht mit einer direkten Linie zu
verbinden, sondern dafür einen ausgeklügelten Wegfindungs-Algorithmus zu
verwenden, um Links nicht quer über andere Components zu zeichnen.
Ein weiterer interessanter Aspekt wäre es, die in [5] vorgestellten Möglichkeiten des GUI-Renderings in die Component-Link-View einzubauen. Somit wäre eine intuitivere Interaktion mit den Geräten möglich, da anstatt
der derzeit verwendeten Textfelder zur Werteingabe je nach Port-Typ passende GUI-Elemente, wie Auswahlboxen, Regler und Auswahllisten, darge1
Mittlerweile in KNX als Nachfolger-Technologie aufgegangen. Siehe auch: http://www.
konnex.org/
KAPITEL 7. FAZIT
88
stellt werden könnten. Das GUI würde dann mehr zur interaktiven Nutzung
inspirieren und nicht nur den automatisierten Modus in den Vordergrund
stellen.
Diese Erweiterung in Kombination mit einer angepassten ComponentLink-View könnte auch für eine multimediale Installation interessant sein,
bei der die Besucher über einen großen, Berührungs-sensitiven Bildschirm
Kopplungen erstellen und löschen könnten, um damit eine Multimedia-Anwendung zu steuern.
7.3
Schlussbemerkung
Die Stärke von Torem liegt in der Entwicklung von Prototypen. Durch das
Koppeln der Komponenten kann recht schnell eine bestimmte Funktionalität getestet werden, ohne ein Programmier-Projekt anlegen zu müssen, die
externen Bibliotheken zu konfigurieren, usw.
Programmen, die hohe Leistungen bieten müssen, wird der generische
Ansatz von Torem u. U. nicht leistungsfähig oder konfigurierbar genug sein.
Solche Programme sind mit einer eigenständigen Implementierung vermutlich besser bedient. Doch für Systeme, die keine optimierte Kommunikation zwischen den Komponenten benötigen, kann mit Hilfe von Torem eine
vollständige, stabile Applikation erstellt werden, die durch das Abspeichern
in eine XML-Datei leicht von Host zu Host portierbar ist.
Anhang A
Entwicklung der
If-Component
An dieser Stelle wird die Entwicklung der If-Component (s. Abb. A.1) detailiert erläutert, um einen Einblick zu geben, wie eigene Components implementiert werden können. Der komplette Quellcode sowie viele weitere Components sind auf der CD im Verzeichnis des Standard-Ingredients-Bundles
zu finden.
Das Grundgerüst der Klasse If sieht so aus:
package net . bebedizo . torem . standardingredients . component ;
import
import
import
import
net . bebedizo . torem . component . AbstractComponent ;
net . bebedizo . torem . component . ComponentFactory ;
net . bebedizo . torem . component . Port ;
net . bebedizo . torem . component . PortImpl ;
import org . osgi . util . tracker . ServiceTracker ;
public class If extends AbstractComponent
{
// Private Instanzvariablen
public If ( long id , ComponentFactory componentFactory ,
ServiceTracker listenerTracker )
{
// Anlegen der Ports
}
public void portActivated ( String portId , Object val )
{
// Behandeln von Wert - Zuweisungen und der
// Aktivierung . Die Logik - Implementierung .
}
}
89
ANHANG A. ENTWICKLUNG DER IF-COMPONENT
90
Abbildung A.1: Die If-Component, wie sie (in der deutschen Lokalisierung)
in der Component-Link-View dargestellt wird.
Die Ports dieser Component werden als private Instanzvariablen angelegt:
// Der PIP , der die Component aktiviert .
private Port test ;
// Der DIP , der die Bedingung für die
// if - Anweisung repräsentiert .
private Port condition ;
// Der POP , der bei true aktiviert wird .
private Port truePort ;
// Der POP , der bei false aktiviert wird .
private Port falsePort ;
// Interner Zwischenspeicher für den Wert den der
// condition - Port zuletzt zugewiesen bekam .
private boolean c ;
Der Konstruktor erzeugt die vier Ports und registriert die Component
selbst als PortListener bei den Input-Ports.
public If ( long id , ComponentFactory componentFactory ,
ServiceTracker listenerTracker )
{
super ( id , componentFactory , componentFactory
. getName () ) ;
// Anlegen der Ports .
test = new PortImpl ( " 0 test " , id , " test " ,
true , null , listenerTracker ) ;
condition = new PortImpl ( " condition " , id , " condition " ,
true , Boolean . class , listenerTracker ) ;
truePort = new PortImpl ( " 0 true " , id , " true " ,
false , null , listenerTracker ) ;
falsePort = new PortImpl ( " 1 false " , id , " false " ,
false , null , listenerTracker ) ;
// Registrieren als PortListener
test . addPortListener ( this ) ;
condition . addPortListener ( this ) ;
ANHANG A. ENTWICKLUNG DER IF-COMPONENT
91
// Damit die Ports via
// getInputPorts und
// getOutputPorts
// von außen sichtbar sind .
inputPortMap . put ( test . getId () , test ) ;
inputPortMap . put ( condition . getId () , condition ) ;
outputPortMap . put ( truePort . getId () , truePort ) ;
outputPortMap . put ( falsePort . getId () , falsePort ) ;
}
Bisher war alles nur Teil der äußerlichen Repräsentation. Nun folgt die
Implementierung der Logik dieser Component. Die Methode portActivated
wird bei jeder Wertzuweisung des condition-Ports und bei jeder Aktivierung
des test-Ports aufgerufen.
public void portActivated ( String portId , Object val )
{
if ( portId . equals ( condition . getId () ) )
{
// Wenn der condition - Port einen neuen Wert erhielt
c = ( Boolean ) val ;
}
else if ( portId . equals ( test . getId () ) )
{
// Wenn der test - Port aktiviert wurde
if ( c )
{
// Aktiviere den true - Port , falls
// c == true gilt
truePort . activate ( null ) ;
}
else
{
// Aktiviere den false - Port , falls
// c == false gilt
falsePort . activate ( null ) ;
}
}
}
Anhang B
Inhalt der CD-ROM
File System: ISO9660
Mode: Single-Session (CD-ROM)
B.1
Diplomarbeit
Pfad:
/
DA.dvi . .
DA.pdf .
DA.ps . .
README
B.2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Diplomarbeit (DVI1 -Datei)
Diplomarbeit (PDF2 -Datei)
Diplomarbeit (PostScript-Datei)
Hinweise zur Benutzung von Torem
Literatur
Die referenzierten Online-Quellen, nach Kapiteln sortiert als PDFs und im
HTML3 -Format.
Pfad:
/literatur/
index.html . . . . . . . .
*/ . . . . . . . . . . . .
1
Mini-Website zum komfortablen Navigieren
zwischen den Online-Literaturquellen
Online-Literatur zum entsprechenden Kapitel
Device Independent – ein Dateiformat. Siehe auch: http://www.math.umd.edu/
∼asnowden/comp-cont/dvi.html
2
Portable Document Format. Siehe auch: http://partners.adobe.com/public/developer/
pdf/index reference.html
3
Hypertext Markup Language. Siehe auch: http://www.w3.org/MarkUp/
92
ANHANG B. INHALT DER CD-ROM
B.3
Bilder und Grafiken
Pfad:
/bilder/
*.eps . . . . . . . . . . .
Bilder und Grafiken dieser Diplomarbeit im
EPS4 -Format.
B.4
Ausführbare Dateien
Pfad:
/torem/
Torem-1.0-Setup.exe . .
Torem-1.0.zip . . . . . .
B.5
93
Installationsprogramm für Torem
Die Vollinstallation als ZIP-komprimierte
Datei
Quelldateien
Die einzelnen Bundles wurden als separate Plugin-Projekte für Eclipse entwickelt. Die folgende Auflistung verwendet eine abgekürzte Schreibweise der
Ordner (die den Namen der Bundles entsprechen), da die Ordnernamen teilweise sehr lang sind. Neben dem Auslassen ([...]) ganzer Package-Teile werden folgende Abkürzungen verwendet: cl für componentlink, cf für componentfactory, conv für converter und stdingredients für standardingredients.
Pfad:
/torem/source/
build.xml . . . . . . . .
it.[...].basedriver/ . . .
it.[...].extra/ . . . . .
net.[...].upnp/ . . . .
net.[...].controlpoint/
.
.
.
.
net.[...].eib/ . . . . . . .
net.[...].component/
net.[...].converter/ .
net.[...].gui/ . . . . .
net.[...].all/ . . . . .
4
.
.
.
.
.
.
.
.
Eine Ant5 -Datei zum Kompilieren und
Erstellen der Bundles
Das UPnP Base Driver Bundle
Das UPnP Base Driver Zusatz-Bundle
Das UPnP-Basisfunktions-Bundle
Das UPnP Bundle (zur Integration von
UPnP-Geräten in Torem)
Das UPnP-EIB Bundle (zur Integration von
EIB-Geräten in UPnP)
Das Component Bundle
Das Converter Bundle
Das GUI-Basis-Bundle
Das Component-Factory-GUI-Bundle für die
Anzeige aller CFs
Encapsulated Postscript. Siehe auch: http://partners.adobe.com/public/developer/en/
ps/5002.EPSF Spec.pdf
5
http://ant.apache.org/
ANHANG B. INHALT DER CD-ROM
net.[...].all.de/ . . . . .
net.[...].all.en/ . . . . .
net.[...].cf.standard/ . .
net.[...].cf.standard.de/
net.[...].cf.standard.en/
net.[...].cf.upnp/ . . . .
net.[...].cl.standard/ . .
net.[...].cl.standard.de/
net.[...].cl.standard.en/
net.[...].conv.standard/
net.[...].logger/ . . . . .
net.[...].link/ . . . . . .
net.[...].client/ . . . . .
net.[...].server/ . . . . .
net.[...].position/ . . . .
net.[...].stdingredients/
net.[...].connection/ . .
org.[...].xerces/ . . . . .
org.[...].upnp/ . . . . .
org.kxml2/ . . . . . . .
Die deutsche Lokalisierung für das
All-Component-Factory-GUI-Bundle
Die englische Lokalisierung für das
All-Component-Factory-GUI-Bundle
Das Component-Factory-GUI-Bundle für die
Anzeige der Standard Ingredient CFs
Die deutsche Lokalisierung für das
Standard-Component-Factory-GUI-Bundle
Die englische Lokalisierung für das
Standard-Component-Factory-GUI-Bundle
Das Component-Factory-GUI-Bundle für die
Anzeige der UPnP-CFs
Das Component-Link-Bundle
Die deutsche Lokalisierung für das
Component-Link-Bundle
Die englische Lokalisierung für das
Component-Link-Bundle
Das Converter-GUI-Bundle
Ein Bundle zum Visualisieren der geloggten
Werte
Das Link Bundle
Das Network-Client-Bundle
Das Network-Server-Bundle
Das Position Bundle
Das Standard Ingredients Bundle
Das Netzwerk-Basis-Bundle
Das Apache Xerces6 Bundle
Das Cyberlink-Bibliothek-Bundle
Das kxml27 Bundle
B.6
Externe Bibliotheken
Pfad:
/torem/lib/
osgi.core.jar . . . . . . .
osgi.compendium.jar . .
6
7
http://xerces.apache.org/
http://www.kxml.org/
94
Der CORE-Teil der OSGi-Spezifikation
Der COMPENDIUM-Teil der
OSGi-Spezifikation
ANHANG B. INHALT DER CD-ROM
B.7
Abhängigkeiten
Pfad:
/dependencies/
Falcon/ . . . . . . . . .
Eiblet/ . . . . . . . . . .
Beinhaltet notwendige Dateien zum Nutzen
des UPnP-EIB-Treibers
Beinhaltet notwendige Dateien zum Nutzen
des UPnP-EIB-Treibers
B.8
Beispiel-Mappings
Pfad:
/samples/
*.xml . . . . . . . . . .
Im XML-Format abgespeicherte Mappings
B.9
Sonstige Dateien
Pfad:
/
torem/mapping.xsd . .
95
XML-Schema für die XML-Dateien zum
Speichern erstellter Mappings
Abkürzungsverzeichnis
API . . . . . . . . . . . . .
BSD . . . . . . . . . . . . .
CF . . . . . . . . . . . . . .
CM . . . . . . . . . . . . . .
CORBA . . . . . . . . .
DIP . . . . . . . . . . . . .
DK . . . . . . . . . . . . . .
DLL . . . . . . . . . . . . .
DOP . . . . . . . . . . . .
DVI . . . . . . . . . . . . .
EIB . . . . . . . . . . . . .
EPS . . . . . . . . . . . . .
GNU . . . . . . . . . . . .
GPL . . . . . . . . . . . . .
GUI . . . . . . . . . . . . .
HTML . . . . . . . . . . .
HTTP . . . . . . . . . . .
IDL . . . . . . . . . . . . .
IIOP . . . . . . . . . . . .
IP . . . . . . . . . . . . . . .
J2SE . . . . . . . . . . . .
JAR . . . . . . . . . . . . .
JDK . . . . . . . . . . . . .
JMF . . . . . . . . . . . . .
JRMP . . . . . . . . . . .
JVM . . . . . . . . . . . .
l10n . . . . . . . . . . . . .
LAN . . . . . . . . . . . . .
LGPL . . . . . . . . . . .
LM . . . . . . . . . . . . . .
MICO . . . . . . . . . . .
MIDI . . . . . . . . . . . .
MVC . . . . . . . . . . . .
OMG . . . . . . . . . . . .
Application Programming Interface
Berkeley Software Distribution
Component Factory
Component Manager
Common Object Request Broker Architecture
Daten-Input-Port
Daten-Kopplung
Dynamic Link Library
Daten-Output-Port
Device Independent
European Installation Bus
Encapsulated Postscript
GNU is not Unix
General Public License
Graphical User Interface
Hypertext Markup Language
Hypertext Transfer Protocol
Interface Definition Language
Internet InterORB Protocol
Internet Protocol
Java 2 Standard Edition
Java Archive
Java Development Kit
Java Media Framework
Java Remote Method Protocol
Java Virtual Machine
Localization: ‘l’ + 10 Buchstaben + ‘n’
Local Area Network
Library (oder Lesser) General Public License
Link Manager
Mico is Corba
Musical Instrument Digital Interface
Model View Control
Object Management Group
96
ABKÜRZUNGSVERZEICHNIS
OSGi . . . . . . . . . . . .
OSI . . . . . . . . . . . . . .
PDE . . . . . . . . . . . . .
PDF . . . . . . . . . . . . .
PIP . . . . . . . . . . . . . .
PK . . . . . . . . . . . . . .
POP . . . . . . . . . . . . .
RMI . . . . . . . . . . . . .
RPC . . . . . . . . . . . . .
SAM . . . . . . . . . . . .
SMS . . . . . . . . . . . . .
SOAP . . . . . . . . . . .
Socam . . . . . . . . . . .
TCP . . . . . . . . . . . . .
UPnP . . . . . . . . . . .
VSL . . . . . . . . . . . . .
W3C . . . . . . . . . . . .
WSDL . . . . . . . . . . .
XML . . . . . . . . . . . .
Open Services Gateway Initiative
Open Systems Interconnection
Plugin Development Environment
Portable Document Format
Programmfluss-Input-Port
Programmfluss-Kopplung
Programmfluss-Output-Port
Remote Method Invocation
Remote Procedure Call
Sensor Aktuator Module
Short Message Service
Simple Object Access Protocol
Service Oriented Context Aware Middleware
Transport Control Protocol
Universal Plug and Play
Virtools Scripting Language
World Wide Web Consortium
Web Services Description Language
Extensible Markup Language
97
Literaturverzeichnis
[1] Ahamer, I. R.: Unified Generic Control Point – Entwicklung einer
Steuerinstanz für Universal-Plug-and-Play- und Jini-fähige Geräte. Diplomarbeit, Fachhochschule Hagenberg, Software Engineering, Hagenberg, Austria, Juni 2003.
[2] Cetus Team: Cetus Links: 16604 Links on Objects and Components /
Distributed Objects & Components: CORBA ORBs. URL, http://www.
cetus-links.org/oo%5Fobject%5Frequest%5Fbrokers.html, Oktober 2005.
Kopie auf CD-ROM.
[3] Comer, D. E.: Computernetzwerke und Internets. Pearson Studium,
Munich, 2 Aufl., 2000.
[4] Deitsch, A. und D. Czarnecki: Java Internationalization. O’Reilly
& Associates, Inc., Sebastopol, CA, USA, März 2001.
[5] Doppler, J. S.: Erstellung von Interfaces zur Steuerung verteilter Anwendungen am Beispiel UPnP-fähiger Eingabegeräte und automatisierter GUI-Generatoren. Diplomarbeit, Fachhochschule Hagenberg, Digitale Medien, Hagenberg, Austria, Juni 2006.
[6] Eclipse Foundation Inc.: Equinox OSGi Transition Proposal .
URL, http://www.eclipse.org/equinox/documents/transition.html, September 2005. Kopie auf CD-ROM.
[7] Emberger, E. N.: Janus—A Service-Oriented Middleware for Distributed Applications with a Multimodal User Interface. Diplomarbeit,
Fachhochschule Hagenberg, Software Engineering, Hagenberg, Austria,
August 2004.
[8] Gamma, E., R. Helm, R. Johnson und J. Vlissides: Entwurfsmuster . Addison-Wesley, Munich u. a., 2004.
[9] Gu, T., H. K. Pung und D. Q. Zhang: Towards an OSGi-Based
Infrastructure for Context-Aware Applications. IEEE Pervasive Computing, 3(4):66–73, Oktober–Dezember 2004.
98
LITERATURVERZEICHNIS
99
[10] Halsall, F.: Data Communications, Computer Networks and Open
Systems. Addison-Wesley, 4 Aufl., 1995.
[11] Hitthaler, T.: Generative Erzeugung von Design mit vvvv . Diplomarbeit, Fachhochschule Salzburg, MultiMediaArt, Vienna, Austria, Mai
2005.
[12] Ircam – Centre Pompidou: A brief history of MAX . URL, http:
//freesoftware.ircam.fr/article.php3?id article=5, 1998. Kopie auf CDROM.
[13] Kowalk, W. P. und M. Burke: Rechnernetze. B. G. Teubner Stuttgart, Stuttgart, 1994.
[14] Kurose, J. F. und K. W. Ross: Computer Networking: A Top-Down
Approach Featuring the Internet. Addison-Wesley, 2 Aufl., 2003.
[15] Meso: vvvv – a multipurpose toolkit. URL, http://vvvv.meso.net/, Mai
2006. Kopie auf CD-ROM.
[16] mico/E: The mico/E project - an OSS CORBA implementation in
Eiffel . URL, http://www.math.uni-goettingen.de/micoe/, Februar 1999.
Kopie auf CD-ROM.
[17] Microsoft: .NET Remoting.
URL, http://msdn.microsoft.com/
library/default.asp?url=/library/en-us/dndotnet/html/hawkremoting.asp,
Juli 2001. Kopie auf CD-ROM.
[18] Object Management Group: Naming Service Specification. URL,
http://www.omg.org/docs/ptc/00-08-07.pdf, August 2000. Kopie auf
CD-ROM.
[19] Object Management Group: CORBA FAQ. URL, http://www.
omg.org/gettingstarted/corbafaq.htm, Januar 2006. Kopie auf CD-ROM.
[20] OSGi Alliance: OSGi Service Gateway Specification. URL, http:
//osgi.org/, Mai 2000. Kopie auf CD-ROM.
[21] OSGi Alliance: About the OSGi Platform. URL, http://osgi.org/
documents/osgi technology/osgi-sp-overview.pdf, Juli 2004. Kopie auf
CD-ROM.
[22] OSGi Alliance: OSGi Service Platform Core Specification. URL,
http://osgi.org/, August 2005. Kopie auf CD-ROM.
[23] OSGi Alliance: OSGi Service Platform Service Compendium. URL,
http://osgi.org/, August 2005. Kopie auf CD-ROM.
LITERATURVERZEICHNIS
100
[24] OSGi Alliance: OSGi Members.
URL, http://osgi.org/about/
member list.asp?section=1, März 2006. Kopie auf CD-ROM.
[25] OSGi Alliance: OSGi Products. URL, http://osgi.org/products/
products.asp?section=3, März 2006. Kopie auf CD-ROM.
[26] Puckette, M. S.: Combining Event and Signal Processing in the MAX
Graphical Programming Environment. Computer Music Journal, 15:68–
77, 1991.
[27] Puckette, M. S.: Max at seventeen. Computer Music Journal, 26:31–
43, 2002.
[28] Puder, A. und K. Römer: Middleware für verteilte Systeme: Konzepte und Implementierungen anhand der CORBA-Plattform MICO.
dpunkt-Verlag, Heidelberg, 1 Aufl., 2001.
[29] Richens, P. und M. Nitsche: Mindstage: Towards a Functional Virtual Architecture. In: Proceedings of the 11th International CAAD Futures Conference, S. 331–340, Dordrecht, 2005. Springer.
[30] Schmidt, D., M. Stal, H. Rohnert und F. Buschmann: PatternOriented Software Architecture – Volume 2: Patterns for Concurrent
and Networked Objects. John Wiley & Sons, Ltd, Chichester, UK, 2001.
[31] Schramm, P., E. Naroska, P. Resch, J. Platte, H. Linde,
G. Stromberg und T. Sturm: A Service Gateway for Networked
Sensor Systems. IEEE Pervasive Computing, 3(1):66–74, Januar–März
2004.
[32] Struck, F.: Shaderentwicklung für menschliche Darsteller in 3D Echtzeitanwendungen. Diplomarbeit, Fachhochschule Wedel, Medieninformatik, Wedel, Germany, Februar 2004.
[33] Sun: Java Remote Method Invocation: 3 - RMI System Overview .
URL, http://java.sun.com/j2se/1.5.0/docs/guide/rmi/spec/
rmi-arch4.html, September 2004. Kopie auf CD-ROM.
[34] Sun: Locale (Java 2 Platform SE 5.0). URL, http://java.sun.com/j2se/
1.5.0/docs/api/java/util/Locale.html, September 2004. Kopie auf CDROM.
[35] Sun: Official Specifications for CORBA support in J2SE 5.0 .
URL, http://java.sun.com/j2se/1.5.0/docs/guide/idl/compliance.html,
September 2004. Kopie auf CD-ROM.
[36] Sun: RMI-IIOP Programmer’s Guide. URL, http://java.sun.com/j2se/
1.5.0/docs/guide/rmi-iiop/rmi%5Fiiop%5Fpg.html, September 2004. Kopie auf CD-ROM.
LITERATURVERZEICHNIS
101
[37] Tanenbaum, A. S.: Computernetzwerke. Pearson Studium, Munich,
3 Aufl., 2000.
[38] The Open Group: The Open Group offers $1 million sponsorship. URL, http://www.opengroup.org/press/7jun99%5Fa.htm, Juni
1999. Kopie auf CD-ROM.
[39] Thurner, M.: Middleware für das Haus der Zukunft. Diplomarbeit, Fachhochschule Hagenberg, Medientechnik und -design, Hagenberg, Austria, Juli 2004.
[40] Ullenboom, C.: Java ist auch eine Insel . Galileo Press, Bonn, 4 Aufl.,
2004.
[41] W3C: Web Services. URL, http://www.w3.org/2002/ws/, März 2006.
Kopie auf CD-ROM.
[42] Waldo, J.: The Jini Specifications. Addison-Wesley, Boston, 2000.
Messbox zur Druckkontrolle
— Druckgröße kontrollieren! —
Breite = 100 mm
Höhe = 50 mm
— Diese Seite nach dem Druck entfernen! —
102