Een OSGi-compatibele implementatie van een Java

advertisement
Faculteit Toegepaste Wetenschappen
Vakgroep Informatietechnologie
Voorzitter: Prof. Dr. Ir. P. Lagasse
Een OSGi-compatibele implementatie van een Java
Resource Monitor voor TabletPC
door
Bruno Van Den Bossche
Promotor: Prof. Dr. Ir. F. Gielen
Scriptiebegeleider: N. Goeminne
Scriptie ingediend tot het behalen van de academische graad van
licenciaat in de informatica
Academiejaar 2003–2004
Faculteit Toegepaste Wetenschappen
Vakgroep Informatietechnologie
Voorzitter: Prof. Dr. Ir. P. Lagasse
Een OSGi-compatibele implementatie van een Java
Resource Monitor voor TabletPC
door
Bruno Van Den Bossche
Promotor: Prof. Dr. Ir. F. Gielen
Scriptiebegeleider: N. Goeminne
Scriptie ingediend tot het behalen van de academische graad van
licenciaat in de informatica
Academiejaar 2003–2004
Een OSGi-compatibele implementatie van
een Java Resource Monitor voor TabletPC
door
Bruno Van Den Bossche
Academiejaar 2003–2004
Promotor: Prof. Dr. Ir. F. Gielen
Scriptiebegeleider: N. Goeminne
Faculteit Toegepaste Wetenschappen
Universiteit Gent
Vakgroep Informatietechnologie
Voorzitter: Prof. Dr. Ir. P. Lagasse
Samenvatting
Adaptieve software kan zich aanpassen aan de omgeving waarbinnen deze gebruikt wordt. Het
bekomen van informatie over de omgeving impliceert het gebruik van heel specifieke programmabibliotheken en functies. Het gevolg hiervan is dat de adaptieve software erg platformspecifiek
dreigt te worden. De adaptiviteit van de software wordt hierdoor beperkt.
De oplossing die in deze thesis uitgewerkt wordt, is in een platformonafhankelijke bibliotheek te
voorzien die alle noodzakelijke gegevens over het gebruikte platform op een eenduidige manier
beschikbaar maakt. Deze bibliotheek is in Java geschreven, mits het gebruik van de Java Native
Interface, en wordt verpakt in een OSGi-bundel. OSGi is een framework-specificatie die toelaat
om op een heel eenvoudige manier software te installeren, updaten en te verwijderen. Wat het
dus uitermate geschikt maakt om als basis voor adaptieve software te gebruiken.
Voor deze thesis werd een TabletPC met het besturingsysteem WindowsXP Tablet Edition als
referentieplatform gebruikt.
Trefwoorden
OSGi, Java, J2ME, JNI, JMF, resource monitoring, adaptieve software.
Toelating tot bruikleen
“De auteur geeft de toelating deze scriptie voor consultatie beschikbaar te stellen en delen van
de scriptie te kopiëren voor persoonlijk gebruik.
Elk ander gebruik valt onder de beperkingen van het auteursrecht, in het bijzonder met betrekking tot de verplichting de bron uitdrukkelijk te vermelden bij het aanhalen van resultaten uit
deze scriptie.”
Bruno Van Den Bossche, mei 2004
Dankwoord
Een scriptie schrijven is iets dat tijdens je hele studentenloopbaan steeds ver weg lijkt, maar plots
zit je in het laatste jaar en sta je er voor. Het is een hele opgave, één waar je vol enthousiasme
aan werkt, maar ook af en toe vervloekt. Gelukkig sta je nooit alleen en daarom zou ik graag
van deze gelegenheid gebruik maken om een aantal mensen te bedanken.
Zo is er professor Frank Gielen, die als promotor dit alles heeft mogelijk gemaakt. Nico Goeminne als onze dagelijkse begeleider, die niet alleen zijn persoonlijke TabletPC beschikbaar stelde,
maar ons ook met raad en daad bijstond tijdens het hele proces en dit met een ontembaar
enthousiasme. Ik heb het hier over ’ons’ want een belangrijk deel van deze scriptie is in samenwerking met Koen Van Boxstael verwezenlijkt. Deze samenwerking heeft zeker bijgedragen tot
de kwaliteit van het werk dat nu voor u ligt, en met twee weet je echt altijd meer dan alleen.
Vandaar ook een welgemeende ’Bedankt Koen’.
Verder wil ik ook nog mijn vriendin Cindy en vrienden Christophe, Inge, Bart, Raf en Joachim
vermelden omdat ze me mijn verhaal lieten doen en voor de nodige ontspanning zorgden tijdens
dit toch wel drukke thesisjaar. Tot slot wil ik ook mijn ouders bedanken om er altijd voor me
te zijn.
Bruno Van Den Bossche, mei 2004
INHOUDSOPGAVE
i
Inhoudsopgave
1 Een nieuwe softwarewereld
1.1 Vereisten . . . . . . . . . . . . . . . .
1.1.1 Software . . . . . . . . . . . . .
1.1.2 Platform . . . . . . . . . . . . .
1.2 Voordelen . . . . . . . . . . . . . . . .
1.2.1 Ontwikkeling en onderhoud . .
1.2.2 Gebruik . . . . . . . . . . . . .
1.2.3 Economisch . . . . . . . . . . .
1.3 Problemen en oplossingen . . . . . . .
1.3.1 Software is platformafhankelijk
1.3.2 Installatie en deı̈nstallatie . . .
1.4 Doelstelling . . . . . . . . . . . . . . .
1.5 Overzicht . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
2
2
2
2
3
4
4
5
5
6
6
7
2 Onderzoek
2.1 OSGi . . . . . . . . . . . . . . . . . . . .
2.1.1 Wat is OSGi? . . . . . . . . . . .
2.1.2 Hoe werkt OSGi? . . . . . . . . .
2.1.3 Voordelen van OSGi . . . . . . .
2.1.4 OSGi implementaties . . . . . . .
2.1.5 OSGi en deze thesis . . . . . . .
2.2 J2ME . . . . . . . . . . . . . . . . . . .
2.2.1 Wat is J2ME? . . . . . . . . . .
2.2.2 Configuraties . . . . . . . . . . .
2.2.3 Profielen . . . . . . . . . . . . . .
2.2.4 J2ME en deze thesis . . . . . . .
2.3 Java Native Interface . . . . . . . . . . .
2.3.1 Wat is de Java Native Interface?
2.3.2 Werking van JNI . . . . . . . . .
2.3.3 JNI en deze thesis . . . . . . . .
2.4 Doelplatformen . . . . . . . . . . . . . .
2.5 Java Community Process . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
8
8
8
9
11
12
13
13
13
15
16
16
17
17
18
18
19
19
3 De API specificatie
3.1 Resources API . . .
3.1.1 Resources . .
3.1.2 Factorymodel
3.2 Monitoring API . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
21
23
23
25
27
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
INHOUDSOPGAVE
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
27
29
31
32
34
39
4 De implementatie
4.1 Algemene Structuur . . . . . . . . . . . . . . . . . .
4.1.1 Scheiding tussen specificatie en implementatie
4.1.2 Platformonafhankelijke code . . . . . . . . . .
4.1.3 Platformafhankelijke code . . . . . . . . . . .
4.2 Implementatie van een Resource: RAM . . . . . . .
4.2.1 Platformonafhankelijke code . . . . . . . . . .
4.2.2 Platformafhankelijke code . . . . . . . . . . .
4.3 Implementatie van de Monitor . . . . . . . . . . . .
4.3.1 MonitorService . . . . . . . . . . . . . . . .
4.4 Integratie met het OSGi-framework . . . . . . . . . .
4.4.1 Bundels . . . . . . . . . . . . . . . . . . . . .
4.5 Problemen en opmerkingen . . . . . . . . . . . . . .
4.5.1 Speciale resources . . . . . . . . . . . . . . .
4.5.2 Het wiel opnieuw uitvinden . . . . . . . . . .
4.5.3 Niet geı̈mplementeerde resources . . . . . . .
4.5.4 Theorie vs. praktijk . . . . . . . . . . . . . .
4.6 Besluit . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
40
40
41
41
42
42
44
45
47
47
47
48
49
49
49
50
50
53
5 Toepassing
5.1 Resourcemonitor . . . . . . . .
5.2 MediaPlayer . . . . . . . . . . .
5.2.1 Gebruikte resources . .
5.2.2 Instellingen . . . . . . .
5.3 Java Media Framework . . . . .
5.3.1 Installatie . . . . . . . .
5.3.2 Mogelijkheden . . . . .
5.3.3 Alternatieven . . . . . .
5.4 Architectuur . . . . . . . . . .
5.4.1 MultiSourcePlayer . .
5.4.2 Grafische user interface
5.5 OSGi-compatibel . . . . . . . .
5.5.1 Activator . . . . . . . .
5.5.2 Instellingen . . . . . . .
5.6 Besluit . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
54
55
56
56
57
58
59
59
59
60
60
61
61
62
62
63
3.3
3.4
3.2.1 Resourcemonitors .
3.2.2 Monitorservice . .
Gebruik van de API . . .
3.3.1 Resources API . .
3.3.2 Monitoring API . .
Besluit . . . . . . . . . . .
ii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6 Besluit
64
A Een
A.1
A.2
A.3
66
67
67
67
overzicht van OSGi-implementaties
Java Embedded Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
OSCAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Knopflerfish . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
INHOUDSOPGAVE
iii
A.4 Service Management Framework . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.5 Overzicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
68
B Ledenlijst OSGi
70
C Beknopt overzicht van de API
72
D Beknopt overzicht van de implementatie
74
E API specificatie changelog
75
F Howto: gebruik van de API
F.1 Opmerkingen . . . . . . . . . . .
F.2 Gebruik van resources en OSGi .
F.2.1 Broncode . . . . . . . . .
F.2.2 Compileren . . . . . . . .
F.2.3 Inpakken in een JAR-file
F.3 Gebruik van een default Monitor
F.3.1 Code . . . . . . . . . . . .
F.3.2 Compileren . . . . . . . .
F.3.3 Inpakken in een JAR-file
F.4 Een BatterijMonitor . . . . . . .
F.4.1 Code . . . . . . . . . . . .
G Handleiding MediaPlayer
G.1 Input . . . . . . . . . . .
G.2 Startscherm . . . . . . .
G.3 Preferences . . . . . . .
G.3.1 Algemeen . . . .
G.3.2 Bestandskeuze .
G.3.3 Schermgrootte .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
77
77
77
78
79
79
80
80
82
82
83
83
.
.
.
.
.
.
85
85
85
86
86
87
87
H Tools
89
I
90
cd-rom
Bibliografie
91
LIJST VAN FIGUREN
iv
Lijst van figuren
2.1
2.2
2.3
2.4
Structuur van het service platform . . . . . . . . . . . . . . . . . . . . . . . . . .
Schematisch overzicht van de beschikbare Java-platformen en hun onderlinge verhouding. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Schematisch overzicht van de J2ME configuraties en profielen. . . . . . . . . . . .
JNI vormt een brug tussen een native taal en Java. . . . . . . . . . . . . . . . . .
14
15
17
3.1
3.2
3.3
3.4
3.5
(a) Request-response model, (b) Event model
De hiërarchie van de resources . . . . . . . . .
De factoryklasse SystemResourceFactory .
De hiërarchie van de monitors . . . . . . . . .
Gebruik van het monitorgedeelte van de API
.
.
.
.
.
22
23
26
28
35
4.1
4.2
De verschillende lagen in de implementatie. . . . . . . . . . . . . . . . . . . . . .
(a) Het eenvoudigste geval met een één op één relatie, (b) Een meer complexe
structuur van geheugens en storage-devices. . . . . . . . . . . . . . . . . . . . . .
42
5.1
5.2
5.3
(a) Monitor van het CPU-gebruik, (b) Monitor van het RAM-gebruik. . . . . . .
De mediaplayer in actie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
De implementatie-klasse van de mediaplayer met de belangrijkste methoden. . .
55
57
61
G.1
G.2
G.3
G.4
Startscherm van de MediaPlayer . . . . . . . . .
Instellen welke acties mogen ondernomen worden.
Instellingen voor de bestandswissel. . . . . . . . .
Instellingen voor de schermwissel. . . . . . . . . .
86
86
87
87
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
10
43
Opmerkingen aan de lezer
Tijdens het schrijven van deze thesis werden een aantal conventies aangehouden om de leesbaarheid te verhogen. Een belangrijk deel van het werk bestond immers uit het ontwikkelen van
software en bijgevolg duikt in de tekst ook hier en daar een verwijzing naar de broncode of een
integraal code-voorbeeldje op.
Wanneer er in de doorlopende tekst een verwijzing naar code opduikt, of er klassenamen gebruikt
worden zal dit als volgt aangeduid zijn: De klasse VoorbeeldKlasse laat de gebruiker toe
om via de methode voorbeeldMethode() aan te tonen hoe code in doorlopende tekst wordt
weergegeven.
Wanneer het om een integraal code-voorbeeld gaat wordt dit als volgt aangegeven.
/**Dit is Java-code**/
public void eenMethode() {
System.out.println("Hello World");
}
Af en toe wordt er ook de nadruk gelegd of dient er extra aandacht besteed te worden aan een
bepaalde opmerking, en dat gebeurt dan op deze manier.
EEN NIEUWE SOFTWAREWERELD
1
Hoofdstuk 1
Een nieuwe softwarewereld
Software is alomtegenwoordig. De tijd dat computers hele kamers of zelfs verdiepingen in beslag
namen is reeds lang voorbij. Steeds meer wordt elk elektronisch apparaat ook een (kleine) computer. Natuurlijk bestaan de mainframes nog steeds en ook het rijk van de desktopcomputers
is nog lang niet uit. Ondertussen zijn ook de PDA’s en GSM’s met extra functionaliteit reeds
immens populair. Maar daar eindigt het niet. De toekomst lonkt met wasmachines die automatisch het juiste programma kiezen, ijskasten die zelf bestellingen plaatsen wanneer de melk op
is en wagens die intelligent gaan meesturen en remmen. Deze explosie van ’nieuwe’ apparaten
heeft als gevolg dat er een even grote, zo niet grotere explosie van software ontstaan is. Elk
toestel heeft immers eigen specifieke software nodig.
Er is echter ook de wens om dezelfde software op al deze verschillende toestellen te gebruiken.
Hoe vaak controleert men immers niet of men e-mail ontvangen heeft? Waarom zou men telkens
weer naar een vaste computer moeten lopen enkel en alleen om na te gaan of er nieuwe berichten
zijn. Zou het niet veel makkelijker zijn als we dit vanop de geı̈ntegreerde display van onze ijskast
kunnen doen, of met behulp van onze PDA die we toch overal bij hebben? Wat we dus eigenlijk
willen bereiken is universele software die op een hele reeks van apparaten kan gebruikt worden,
zichzelf kan aanpassen aan de eigenschappen van de apparaten en dit zonder enige aanpassing
of niet triviale tussenkomst van de gebruiker.
Het hoeft ook niet te eindigen bij aanpassingen aan de statische eigenschappen van de apparaten.
Wanneer we het grappige filmpje dat we als e-mail attachment gekregen hebben op onze ijskast
bekijken, willen we uiteraard niet dat dit de normale werking van de ijskast gaat beı̈nvloeden
omdat alle systeemresources opgeslorpt worden. We wensen dus ook software die zich dynamisch
1.1 Vereisten
2
kan aanpassen aan de omstandigheden waarin het toestel zich bevindt.
1.1
Vereisten
Het idee van deze universele en adaptieve software is natuurlijk wel heel mooi, maar het stelt
ook heel wat extra eisen aan de software en aan het onderliggende platform.
1.1.1
Software
Aangezien we willen dat de software op eender welk apparaat gebruikt kan worden, dient deze
software platformonafhankelijk te zijn. Daarnaast moet bij het ontwerpen van de software ook
rekening gehouden worden met de capaciteiten van de mogelijke doelplatformen, bv. het al
dan niet aanwezig zijn van een netwerkverbinding en de bandbreedte ervan. In de software
moeten natuurlijk ook de nodige mechanismen ingebouwd zitten zodat deze zich dynamisch kan
aanpassen.
1.1.2
Platform
De eisen van platformonafhankelijkheid en kennis van de capaciteiten van het gebruikte platform
lijken tegenstrijdig. Het is niet mogelijk om dit op een triviale manier te realiseren. Daarom
is er nood aan een algemene API die op een uniforme manier toelaat om de platformspecifieke
gegevens op te vragen.
Eens we de platformonafhankelijke adaptieve software hebben, zouden we deze uiteraard graag
gebruiken. Maar vaak is het installeren en weer verwijderen van software niet altijd even eenvoudig. Laat staan dat het altijd automatisch kan. Daarom stellen we aan het platform nog
de bijkomende eis, dat het installeren en weer verwijderen van software op een heel eenvoudige
manier kan gebeuren.
1.2
Voordelen
De voorgestelde scenario’s uit de inleiding klinken dan misschien wel futuristisch, deze toekomst
is niet meer zo veraf. Bovendien heeft dit concept nog heel wat meer toepassingsgebieden en
1.2 Voordelen
3
misschien meer concrete voordelen. Zowel naar de gebruiker als ontwikkelaar van de software
toe. We zetten hier de voordelen netjes op een rij.
1.2.1
Ontwikkeling en onderhoud
Eerst en vooral zijn er natuurlijk de voordelen op het gebied van de ontwikkeling en het onderhoud van de software.
Ontwikkelen van de software
Write once...
Een populair concept, dat vooral in de open source wereld gepromoot wordt, is
’write once, compile everywhere’, wat dus wil zeggen dat men software éénmaal goed schrijft en
men vervolgens de broncode overal kan compileren tot een uitvoerbaar programma. Uiteraard
blijven we ook dit concept hanteren.
Compile once...
Om onze doelstellingen te bereiken, dienen we echter nog een stap verder
te gaan: de code slechts éénmaal compileren. Dit concept wordt ook vandaag al toegepast en
gebruikt, namelijk in de wereld van de virtuele machines, zoals gebruikt bij Java en .NET. Op
deze manier wordt de gecompileerde code dan uitgevoerd door de virtuele machine, onafhankelijk
van het platform waarop deze virtuele machine zelf draait.
Run everywhere... (really!)
Het vorige punt doet misschien vermoeden dat de software
reeds op alle mogelijke platformen waarvoor de virtuele machine bestaat kan uitgevoerd worden.
Dit is tot op zekere hoogte waar, maar de software zal zich niet aanpassen aan het toestel waarop
deze gebruikt wordt. Of de software gaat uit van bepaalde onderstellingen over de hardware,
wat deze ongeschikt maakt voor toestellen die hier niet aan voldoen.
Testen en debuggen
Aangezien er maar één software-versie bestaat, moet er uiteraard maar één versie getest en
gedebugged worden. Het is niet nodig dat de software op alle mogelijke doelapparaten apart
dient getest te worden. In belangrjke mate zal het testwerk op een standaardplatform kunnen
uitgevoerd worden, en dient slechts in de eindfase getest te worden met specifieke apparaten.
Dit zal ook de ontwikkelingscyclus versnellen.
1.2 Voordelen
4
Onderhoud
Het onderhoud van de code wordt beperkt tot één versie, wijzigingen dienen slechts éénmaal
gemaakt te worden. Hetzelfde geldt voor uitbreidingen. De ondersteuning van nieuwe platformen
zal zelfs geen extra ingrepen vereisen.
Handleiding
De handleiding voor de software dient slechts éénmaal geschreven te worden. Hoewel de software
er misschien anders kan uitzien op de verschillende platformen gaat het immers echt om hetzelfde
pakket, dat bijgevolg één handleiding nodig heeft.
1.2.2
Gebruik
Wat betreft gebruiksgemak maken we eveneens een sprong voorwaarts. De eindgebruiker dient
immers slechts éénmaal het gebruik van het pakket aan te leren. Ook hier is de opmerking
terecht dat het pakket er op verschillende platformen anders kan uitzien, maar de gebruikte
concepten en manier van werken blijven hetzelfde. Iets wat in het geval van totaal verschillende
pakketten niet noodzakelijk het geval zal zijn.
1.2.3
Economisch
De economische voordelen zijn onrechtstreekse gevolgen van de vorige. Aangezien er slechts
één versie van de software dient ontwikkeld te worden, zijn er uiteraard minder kosten. De
ontwikkelaars dienen niet meer naast elkaar aan hetzelfde probleem te werken op de verschillende
platformen of moeten hun aandacht niet meer over verschillende platformen verdelen. Er hoeft
slechts éénmaal een handleiding geschreven te worden en het pakket kan in één variant verspreid
worden.
Ook voor de eindgebruiker zal de software goedkoper zijn aangezien de aankoop van één versie
zal volstaan om op alle apparaten te gebruiken. Dit waar voordien voor bijna elk apparaat een
andere versie diende aangeschaft te worden.
1.3 Problemen en oplossingen
1.3
5
Problemen en oplossingen
Bij het zoeken naar een omgeving en ontwikkelen van software om de aangehaalde voordelen
waar te maken, stuiten we natuurlijk op een aantal problemen.
1.3.1
Software is platformafhankelijk
Kijken we naar de bestaande software, dan merken we op dat deze grotendeels platformafhankelijk is. Dit houdt in dat je een bepaald softwarepakket niet zonder meer op meerdere verschillende
toestellen kan installeren en gebruiken. Het platformonafhankelijk zijn van software kan zich op
verschillende niveau’s manifesteren.
Broncode
Eerst en vooral is de broncode niet altijd zonder meer porteerbaar naar andere platformen. Dit
kan doordat er onzorgvuldig geprogrammeerd werd, maar veel vaker door het gebruik van platformafhankelijke bibliotheken of soms gewoon omdat de taal en compiler zelf enkel beschikbaar
zijn voor een beperkt aantal platformen.
De oplossing voor dit probleem is relatief eenvoudig en bestaat erin een taal en compiler te kiezen
die beschikbaar zijn voor alle platformen en zich te beperken tot bibliotheken beschikbaar voor
alle platformen.
Uitvoerbare code
Het kiezen van een goede taal is echter niet voldoende. In de compilatiestap wordt de broncode immers omgezet naar uitvoerbare code. Typisch is dit assemblercode voor een specifieke
combinatie van processorarchitectuur en besturingssysteem. Concreet zal de platformonafhankelijke broncode omgezet worden naar platformafhankelijk uitvoerbare code. Dit brengt ons nog
niet ver genoeg, aangezien de uitvoerbare bestanden dan nog steeds verschillend zijn voor alle
platformen.
Om dit probleem op te lossen kan er gebruik gemaakt worden van platformen zoals Java en
.NET. Hier wordt de broncode immers omgezet naar een platformonafhankelijke bytecode. Deze
bytecode wordt vervolgens uitgevoerd door een virtuele machine. De virtuele machine dient dan
1.4 Doelstelling
6
éénmaal geı̈mplementeerd te worden voor alle platformen, en daarna kan deze op alle platformen
waarvoor de virtuele machine bestaat uitgevoerd worden.
Veronderstellingen over het gebruikte platform
Vaak wordt software reeds van bij de eerste stap in het ontwikkelingsproces voor een specifiek
doelplatform ontwikkeld. Het gevolg hiervan is dat heel wat van de ontwerpbeslissingen uitgaan
van een zekere voorkennis van dit platform, bv. de geheugencapaciteit of rekenkracht. Dit
probleem gaat heel wat dieper dan de keuze van taal of virtuele machine en is achteraf ook niet
zo eenvoudig op te lossen.
Gedurende heel het ontwikkelingsproces dient er nauwlettend in de gaten gehouden te worden
welke ontwerpbeslissingen mogelijk zijn. In het ideale geval kan met at runtime nagaan wat wel
en niet kan.
1.3.2
Installatie en deı̈nstallatie
Het installeren en deı̈nstalleren van software is niet altijd een eenvoudige taak. Het is belangrijk
dat dit proces zo eenvoudig mogelijk is. Zeker indien we willen evolueren naar situaties waar de
software ook zichzelf moet kunnen installeren en deı̈nstalleren.
Om dit te kunnen verwezenlijken is het gebruik van een framework zoals OSGi ideaal. Dit laat
toe het installatie- en deı̈nstallatieproces te beschouwen als het eenvoudig in- en uitpluggen van
een stopcontact.
1.4
Doelstelling
Tot zover zijn er een aantal eisen geformuleerd die vervuld dienen te worden, evenals een aantal
problemen met suggesties tot oplossingen.
Het doel van deze thesis bestaat erin:
• Een OSGi-compatibele Java API op te bouwen die toelaat om gegevens over het platform
op te vragen. Deze thesis richt zich vooral naar de mobiele en daardoor vaak meer beperkte apparaten. Dit moet weerspiegeld worden in de API doordat deze geen te hoge
systeemeisen mag stellen.
1.5 Overzicht
7
• In een implementatie van deze API te voorzien.
• Een toepassing te schrijven die gebruik maakt van deze API om de mogelijkheden te
demonstreren.
1.5
Overzicht
In hoofdstuk 2 zullen eerst alle technologieën overlopen en besproken worden om daarna in
hoofdstuk 3 een API op te stellen en in hoofdstuk 4 een concrete implementatie te realiseren.
Tenslotte zal in hoofdstuk 5 een applicatie ontwikkeld worden die de mogelijkheden demonstreert.
Het opstellen van de API gebeurde in samenwerking met Koen Van Boxstael. Aangezien de
onderzoeksfase en de ontwikkeling van de API gemeenschappelijk waren, werden hoofdstuk 2 en
3 samen geschreven. Zo ook appendices A, C en E.
ONDERZOEK
8
Hoofdstuk 2
Onderzoek
Dit hoofdstuk geeft een overzicht van de technologie en het gedane opzoekingswerk nodig voor
het verwezenlijken van deze thesis.
De belangrijkste technologieën die een groot deel van de zoektocht uitmaakten, zijn OSGi (zie
punt 2.1), J2ME (zie punt 2.2) en JNI (zie punt 2.3).
Verder is er ook onderzocht wat de mogelijkheden van de doelplatformen zijn, en welke native
ondersteuning er beschikbaar is om informatie over het systeem op te vragen (zie punt 2.4).
Ten slotte vonden we het ook nuttig eens na te gaan hoe een standaardisatieproces van een Java
specificatie verloopt in het Java Community Process (zie punt 2.5).
2.1
2.1.1
OSGi
Wat is OSGi?
OSGi staat voor Open Services Gateway Initiative. Het is een organisatie die open specificaties
maakt voor het leveren van services over een netwerk aan thuisgebruikers, bedrijven, auto’s en
vele andere omgevingen. Het biedt aan serviceproviders, ontwikkelaars en software-ontwerpers
een gemeenschappelijk raamwerk voor het ontwikkelen en ontplooien van services [1]. Alle
apparaten waarop een implementatie van de OSGi specificaties aanwezig is, kunnen hierbij
gebruikt worden. Daarenboven gebruikt de specificatie Java als taal, wat ervoor zorgt dat
services kunnen ontwikkeld worden op een platformonafhankelijke manier.
2.1 OSGi
9
De eerste specificatie van OSGi in mei 2000 was vooral gericht op het gebruik van het framework
op home network gateways. Dit zijn apparaatjes, zoals set-top boxes en modems, die verbonden
zijn met een netwerk en diensten kunnen aanbieden aan thuisgebruikers. De tweede en derde
release van de specificatie breiden de eerste uit en hebben van OSGi een platform gemaakt dat
voor veel meer apparaten bedoeld is. Tot de mogelijkheden behoren nu ook o.a. PC’s, mobiele
telefoons, allerhande consumer electronics zoals PDA’s, mobiele toepassingen in auto’s . . .
Eén van de scenario’s waarvoor het OSGi framework ontworpen is, is een netwerk beheerd door
een operator waarop een groot aantal service platforms is aangesloten. Deze kunnen services
aanbieden van verschillende serviceproviders. Dit is echter slechts één mogelijk scenario want
de specificatie laat vele andere mogelijkheden open. Een voorbeeld hiervan is Eclipse1 dat sinds
versie 3.0 M5 gebruik maakt van OSGi om het gebruik van plugins mogelijk te maken.
2.1.2
Hoe werkt OSGi?
Het service platform bestaat uit een Java Virtuele Machine (JVM), een implementatie van het
OSGi framework en bundels die erop draaien. Een overzicht van de structuur is te zien in figuur
2.1.
Het besturingssysteem en de hardware
zijn uiteraard de onderste laag. Voor de werking
van OSGi is deze schakel echter niet zo belangrijk. Voor het geheel van de thesis uiteraard wel,
aangezien hier alle systeeminformatie dient opgevraagd te worden. Dit komt uitgebreider aan
bod in punt 2.3.
De Java Virtual Machine zorgt voor een platformonafhankelijke basis waarbinnen het OSGi
framework zich nestelt. Een uitgebreide bespreking van de eisen gesteld aan de JVM volgt in
punt 2.2.
Het OSGi framework
verzorgt dan een gestandaardiseerde omgeving waarbinnen bundels
kunnen geı̈nstalleerd worden. Bundels kunnen dynamisch geladen, gestart, gestopt, geüpdatet
en gedeı̈nstalleerd worden door het framework.
1
een Java IDE, zie http://www.eclipse.org en http://www.aqute.biz/eclipse.html voor meer informatie.
2.1 OSGi
10
Monitor
...
Resources
log
servlet
http
bundels
OSGi framework
Java Virtual Machine
OS & Hardware
Figuur 2.1: Structuur van het service platform
Een bundel
bestaat uit alle Java klassen en andere resources die nodig zijn om een bepaalde
functie aan te bieden aan de gebruiker of om services aan te bieden aan andere bundels. Concreet
zijn het archiefbestanden, JAR of Java ARchive. Het archief bevat een standaard manifest[2]
met enkele specifieke OSGi-headers. Dit manifest is een tekstbestand waarin informatie staat
over de bundel die het framework nodig heeft, zoals een beschrijving van de bundel, de packages
die het nodig heeft, de packages die het zelf ter beschikking stelt en een aanduiding welke klasse
gebruikt moet worden als activator. De activator is een klasse met een start() en een stop()
methode, die aangeroepen worden bij het starten resp. stoppen van de bundel. Op deze manier
kan een bundel geı̈nitialiseerd worden en kan hij zijn resources opruimen bij het stoppen. Na
de start van de bundel zijn de services en de geëxporteerde packages beschikbaar voor andere
bundels. Het framework regelt zelf alle afhankelijkheden tussen bundels.
In figuur 2.1 worden enkele standaardbundels getoond en op hetzelfde niveau de 2 nieuwe bundels
die het resultaat zijn van deze thesis. De uitwerking hiervan volgt in de latere hoofdstukken.
Gedurende zijn levensloop kan een bundel zich in één van de volgende toestanden bevinden:
INSTALLED De bundel is succesvol geı̈nstalleerd en de eventuele native libraries zijn aanwe-
2.1 OSGi
11
zig.
RESOLVED Alle klassen vereist door de bundel zijn aanwezig. De bundel is ofwel klaar
om gestart te worden of is reeds gestopt. Packages die de bundel exporteert worden
beschikbaar gemaakt voor andere bundels wanneer hij voor de eerste keer in deze toestand
terechtkomt.
STARTING De bundel werd gestart, maar het startproces is nog niet beëindigd.
STOPPING De bundel werd gestopt, maar het stopproces is nog niet beëindigd.
ACTIVE De bundel werd succesvol gestart en is momenteel actief. De services die hij heeft
geregistreerd zijn beschikbaar voor andere bundels.
UNINSTALLED De bundel werd gedeı̈nstalleerd. Dit is een eindtoestand en de bundel kan
niet meer van toestand veranderen.
Het installeren, starten, stoppen en deı̈nstalleren van een bundel kan door rechtstreeks commando’s in te geven2 in het OSGi framework of vanuit andere bundels. Deze manier van werken laat
bijvoorbeeld ook toe om bundels vanop afstand te installeren door middel van een beheerdersbundel, bijvoorbeeld onder de vorm van een webinterface.
De overgang tussen de verschillende toestanden kan een aantal events veroorzaken. Zo zal het
installeren van een bundel een BundleEvent veroorzaken, hetzelfde gebeurt voor de andere toestandsovergangen. Een BundleEvent is eigenlijk een event afgeleid van een FrameworkEvent.
Dit kan bijvoorbeeld voorkomen na een fout in het framework, het updaten van packages of
gewoon om aan te geven dat het framework klaar is met opstarten.
Verder is er ook nog het ServiceEvent. Indien een bundel een aantal services beschikbaar
stelt, zal bij het stoppen van de bundel een ServiceEvent gegenereerd worden dat aangeeft
dat de service gestopt wordt. Dit laat toe dat bundels die gebruik maken van deze service hun
resources kunnen vrijgeven zodat deze service kan beëindigd worden. Analoog worden er ook
events gegenereerd bij het registreren, wijzigen. . . van services.
2.1.3
Voordelen van OSGi
De voordelen van het OSGi-framework zijn legio. Enkele van de meest markante zijn:
2
Eigenlijk is de console waar deze commando’s kunnen ingegeven worden niets meer dan een bundel die textuele
commando’s vertaalt naar de juiste methode-oproepen in het framework.
2.1 OSGi
12
Platformonafhankelijk Het OSGi-framework maakt gebruik van het Java-platform, dat zelf
al platformonafhankelijk is. Bijgevolg kan het framework op elk apparaat met Javaondersteuning3 geı̈nstalleerd en gebruikt worden. Bovendien hoeven bundels maar één
keer geschreven te worden in Java, en niet specifiek voor elk type of merk van het doelapparaat.
Eenvoudige (de-)installatie van bundels Het installeren van bundels kan over het netwerk
of van een gegevensdrager. Bovendien is er geen installatie-procedure nodig. De bundel
kan onmiddellijk ingeplugged en gestart worden. Net als de installatie is ook het verwijderen van bundels heel eenvoudig. Alles kan als het ware gebeuren met een eenvoudige
druk op de knop. Een bijkomend voordeel is dat er geen bestanden of referenties in het
besturingssysteem achterblijven, want het is er immers volledig onafhankelijk van.
Open De OSGi-specificatie is open, onafhankelijk van een bepaald bedrijf of platform. Ook heel
algemeen en dus onafhankelijk van het scenario waarvoor het gebruikt zal worden, iedereen
mag en kan een implementatie maken zolang deze maar voldoet aan de specificatie. Het
ontwikkelen van de specificatie gebeurt door de OSGi-leden, een volledige lijst is terug te
vinden als bijlage.
2.1.4
OSGi implementaties
De OSGi Alliance zorgt voor het ontwikkelen en de specificatie van het services platform. Ze
levert zelf echter geen implementatie. Dit wordt overgelaten aan derden. Een aantal van de
momenteel bestaande implementaties zijn:
• Java Embedded Server 2.0 (SUN) [3]
• mBedded Server (Procyst) [4]
• aveLink Embedded Gateway (Atinav) [5]
• Oscar (Open Source Software) [6]
• KnopflerFish (Open Source Software) [7]
Gebaseerd op het Gatespace GDSP OSGi framework [8]
• IBM Service Management Framework (IBM) [9]
3
Elk apparaat dat voldoet aan de CDC/Foundation profile, zie pagina 16
2.2 J2ME
13
Als referentie gateway zullen zowel KnopflerFish als SMF gebruikt worden. Een vergelijking van
een aantal van deze implementaties is als bijlage toegevoegd.
2.1.5
OSGi en deze thesis
Het uiteindelijke doel van ons werk bestaat erin een OSGi-bundel te creëren die onze packages
exporteert, en aldus andere bundels toelaat er gebruik van te maken.
Het framework dat we bouwen maakt gebruik van de Java Native Interface (zie punt 2.3). Het
OSGi-framework laat dit op zijn beurt toe door de native libraries te includeren in de bundels
en het bundelmanifest te voorzien van de Bundle-NativeCode header. In deze header kan
gespecificeerd worden waar de native library voor elk ondersteund besturingssyteem en elke
ondersteunde architectuur te vinden zijn. Afhankelijk van het gebruikte systeem zal het OSGiframework dan zelf uitzoeken welke native library geschikt is. Op die manier is het dus niet
nodig om voor elk platform een aparte bundel te creëren.
2.2
2.2.1
J2ME
Wat is J2ME?
De Java 2 Micro Edition is een sterk geoptimaliseerde Java runtime omgeving, met als doelstelling het gebruik in elektronische gebruiksapparaten. J2ME behelst heel de ruimte van gebruiksapparaten, gaande van smartcards of beepers tot en met geavanceerde apparaten zoals
een set-top box.
Na het ontstaan van Java werd het platform alsmaar verder uitgebreid om de taal zo aantrekkelijk mogelijk te maken voor de commerciële eindgebruikers. De mogelijkheden en grootte
van het Java-platform namen alsmaar toe. Ten tijde van de eerste commerciële release was
er al de noodzaak tot opsplitsing. Er is het J2SE platform, Java 2 Standard Edtion, met de
basisfunctionaliteit. Optionele packages kunnen hieraan toegevoegd worden om aan specifieke
eisen te voldoen. Er was ook een platform gericht naar server- en bedrijfstoepassingen, J2EE,
Java 2 Enterprise Edition. In figuur 2.2 worden de verhoudingen tussen de verschillende platformen grafisch voorgesteld. Merk hierbij op dat J2ME niet enkel een subset is van de andere
platformen.
2.2 J2ME
14
Figuur 2.2: Schematisch overzicht van de beschikbare Java-platformen en hun onderlinge verhouding.
Gedurende die ontwikkeling van Java werden de systeemvereisten groter met elke release. De
vereisten van het Java-platform waren veel te groot geworden voor gebruik in consumentenelektronica, ironisch genoeg net dat waar Java oorspronkelijk voor ontwikkeld was (al heette het
toen nog Oak). Als antwoord hierop creëerde Sun een aantal gereduceerde Java-omgevingen4 ,
elk gericht op een specifiek marktsegment, en allen gebaseerd op JDK 1.1, de voorganger van
Java 2.
Dit is waar J2ME, gebaseerd op Java 2, om de hoek komt kijken. Uiteindelijk zal het de bedoeling
zijn dat het alle voorgaande JDK 1.1-producten vervangt. De doelstellingen van J2ME zijn
heel uitgebreid, en de verschillende toepassingsgebieden hebben heel verschillende en specifieke
eisen. Het is bijgevolg bijna vanzelfsprekend, dat J2ME zelf weer opgesplitst wordt in een aantal
specificaties, elk met een eigen verzameling doelstellingen en toepassingsmogelijkheden, geschikt
voor een bepaalde klasse van consumentenelektronica.
Zo’n subset van de volledige Java programmeeromgeving voor een specifiek toestel wordt gedefinieerd door één of meerdere profielen (profiles) die de basiseigenschappen van een configuratie
(configuration) uitbreiden. Elk profiel stelt extra eisen aan het toestel, waardoor het gamma
van geschikte toestellen kleiner wordt naarmate het gebruik van bijkomende profielen. Een
schematisch overzicht van de verschillende profielen en configuraties is terug te vinden in figuur
2.3.
4
JavaCard, EmbeddedJava, PersonalJava
2.2 J2ME
15
Figuur 2.3: Schematisch overzicht van de J2ME configuraties en profielen.
2.2.2
Configuraties
De configuraties worden opgesplitst aan de hand van een aantal eigenschappen zoals
• De types en hoeveelheid van het beschikbaar geheugen.
• Het type van de processor en zijn snelheid.
• Het type netwerkconnectie beschikbaar voor het toestel.
Een configuratie representeert een minimaal platform en definieert geen optionele features. Dit
om ontwikkelaars toe te laten om hun toepassingen zo platformonafhankelijk mogelijk te maken.
Momenteel zijn er 2 configuraties gedefinieerd:
Connected Limited Device Configuration (CLDC) richt zich tot de low-end toestellen
zoals gsm’s of pda’s met een beschikbaar geheugen van om en bij de 512KiB. Omwille
van deze reden is CLDC dan ook nauw verbonden met wireless Java, dat als doel heeft
om gsm toestellen toe te laten, kleine Java-applicaties (MIDlets) te laten downloaden en
uitvoeren. [10, 11]
Connected Device Configuration (CDC) richt zich tot alle toestellen die tussen de CLDC
configuratie liggen en volwaardige desktopsystemen. Deze toestellen hebben doorgaans
een grotere geheugencapaciteit (2MiB of meer) en krachtigere processors, waardoor ze
bijgevolg een meer volledige Java-omgeving kunnen ondersteunen. [12]
2.2 J2ME
16
Elke configuratie bestaat uit een Java virtual machine en een collectie Java basisklassen die in
een programmeeromgeving voorzien. De beperkingen van de doeltoestellen maken het onmogelijk om het volledige Java platform te ondersteunen. Om die reden zijn de J2ME Virtual
Machines vaak gespecificeerd in termen van die delen van de Java Virtual Machine [13] en de
Java Language Specification [14] die niet ondersteund hoeven te worden. Zo specificeert de
CLDC-specificatie dat de Virtual Machine de types float en double niet moet ondersteunen,
aangezien de onderliggende hardware vaak geen floating point berekeningen ondersteunt.
2.2.3
Profielen
Een profiel breidt een configuratie uit met additionele klassen die features toevoegen specifiek
aan bepaalde apparaten.
Mobile Information Device Profile (MIDP) is gespecificeerd bovenop de CLDC configuratie en is ontworpen voor mobiele telefoons en eenvoudige PDA’s. Het biedt een API
voor user interfaces, netwerkverbindingen, dataopslag en applicatiebeheer.
Foundation Profile (FP) is het eenvoudigste profiel bovenop de CDC configuratie. Het is
ontworpen voor embedded implementaties zonder user interface. De CDC profielen zijn
gelaagd, en bovenop het het FP profiel kunnen dus ook nog andere profielen toegevoegd
worden.
Personal Basis Profile (PBP) is een subset van het PP met ondersteuning voor netwerkconnecties en een beperkte grafische user interface. PBP is gelaagd op het FP.
Personal Profile (PP) is gericht op toestellen die een volledige GUI- en applet-support vereisen, zoals PDA’s, communicator-type toestellen en gameconsoles. Het biedt de volledige
AWT-toolkit en laat toe om web-based applets uit te voeren. Het Personal Profile vervangt
de PersonalJava technologie. PP is gelaagd op het FP.
2.2.4
J2ME en deze thesis
Het doel van deze thesis is een framework te creëren voor het toegankelijk maken en het monitoren van hardware resources op een beperkt mobiel toestel, meer bepaald op een OSGi-gateway.
Uiteraard trachten we geen extra eisen wat betreft systeemvereisten op te leggen dan diegene,
reeds opgelegd door het OSGi-framework. Het gebruik van de Java Native Interface (JNI) is
2.3 Java Native Interface
17
essentieel. Het moet immers mogelijk zijn om rechtstreeks te interageren met het onderliggende
besturingssysteem om toegang te krijgen tot de systemresources. JNI is echter niet beschikbaar
in de CDLC-configuratie, maar wel in de CDC-configuratie. Daarom zal er met het CDC/Foundation Profile gewerkt worden.
2.3
2.3.1
Java Native Interface
Wat is de Java Native Interface?
De Java Native Interface (JNI) [15] is een onderdeel van het Java platform dat een brug vormt
tussen Java en andere programmeertalen zoals C of C++ (zie figuur 2.4). Men noemt deze nietJavacode meestal met de Engelstalige benaming native code. JNI maakt het mogelijk om native
code geschreven in C/C++ aan te roepen vanuit een Java programma. Dit kan bestaande code
zijn die men wil hergebruiken, maar kan ook nieuwe code zijn. Langs de andere kant biedt JNI
ook een mogelijkheid om Java code en een Java Virtual Machine (JVM) aan te roepen vanuit
programma’s geschreven in C of C++.
Java
Native
Functions
Libraries
JNI
Exceptions
Classes
VM
Figuur 2.4: JNI vormt een brug tussen een native taal en Java.
Java is ontworpen om platformonafhankelijk te zijn. Soms kan het echter nodig zijn om toegang
te hebben tot mogelijkheden die niet ondersteund worden door de Java API en wel specifiek
zijn voor de hardware en het besturingssysteem waarop de JVM draait. Het kan ook nodig
zijn om voor zeer rekenintensieve bewerkingen een stukje supergeoptimaliseerde native code te
2.3 Java Native Interface
18
gebruiken. Dit is waarom JNI toegevoegd werd aan het Java platform.
JNI heeft ook nadelen. Ten eerste, Java code die gebruik maakt van native code verliest haar
platformonafhankelijkheid. Alleen op het platform waarvoor de native code geschreven is zal
het programma nog werken. Ten tweede, verliest de programmeur de veiligheid van de Java
taal. Java is fundamenteel verschillend van C/C++. De programmeur moet zeer nauwlettend de omzetting maken tussen Java datatypes en C datatypes en moet zelf instaan voor het
geheugengebruik in de native code.
2.3.2
Werking van JNI
De Java taal heeft een keyword native om aan te duiden dat een methode een native implementatie heeft. Deze methode zal ook een lege implementatie hebben in de Javacode. De
JVM zal bij de uitvoering van een methode die native als modifier heeft de implementatie
niet in het classbestand zoeken, maar in een bibliotheek van native code. De bibliotheek die
moet gebruikt worden, wordt in een Java klasse ingeladen via een oproep van de API methode
System.loadLibrary().
2.3.3
JNI en deze thesis
In onze thesis maken we een API om informatie op te vragen over systeem resources. Verschillende resources zijn systeem-specifiek en zijn ontoegankelijk via de Java API. Voor deze zal
het nodig zijn om API’s te gebruiken van het onderliggende besturingssysteem of van andere
bibliotheken die niet in Java maar in C/C++ geschreven zijn. JNI zal dus onontbeerlijk zijn
om systeeminformatie beschikbaar te stellen aan Java applicaties.
Het komt er dus eigenlijk op neer dat we een Java API zullen definiëren bovenop een bestaande
API. Strikt genomen is het dus eigenlijk niet nodig om dit werk te leveren. De platformspecifieke
API’s zijn echter zeer verschillend waardoor het niet mogelijk is om op een algemene wijze
toegang te krijgen tot de systemresources. Willen we platformonafhankelijke software creëren
die gebruik maakt van de specifieke eigenschappen van het platform, dan is er hoge nood aan een
generieke API die deze resources beschikbaar maakt, op éénzelfde manier voor alle platformen.
2.4 Doelplatformen
2.4
19
Doelplatformen
Uiteraard kan zo goed als elk platform gebruikt worden. De belangrijkste vereiste is de beschikbaarheid van een Java Virtuele Machine. Verder moet deze minstens J2ME CDC/Foundation
Profile ondersteunen om gebruik te kunnen maken van de API. Daarnaast moet er natuurlijk ook
de mogelijkheid bestaan om de gegevens die we willen beschikbaar maken te kunnen opvragen.
Het zal daarom niet mogelijk zijn op elk platform elke resource te ondersteunen.
Deze thesis richt zich vooral op mobiele en daardoor vaak ook beperktere toestellen. Laat dit
nu ook net die groep van apparaten zijn waar het opvragen van de resources niet altijd triviaal
is. Enkele van de mogelijke doelplatformen zijn:
• iPAQ met PocketPC als besturingssysteem. De API’s van deze platformen kunnen gevonden worden op websites van HP [16] en Microsoft [17].
• Het besturingssysteem Symbian [18] dat op diverse mobiele telefoons te vinden is.
• TabletPC met WindowsXP Tablet Edition als besturingssysteem [17].
Deze thesis zal specifiek het platform TabletPC met WindowsXP Tablet Edition als doelplatform
gebruiken.
2.5
Intermezzo: Java Community Process
Het Java Community Process [19] is de manier waarop alle nieuwe Java technologieën ontwikkeld
worden. Iedereen kan hieraan deelnemen, zowel experts, bedrijven en het publiek. Het is het
proces waarmee alle standaarden gemaakt worden die met Java te maken hebben.
Het proces verloopt in grote lijnen als volgt.
Initiation Een lid van JCP doet een voorstel voor een nieuwe specificatie of de wijziging van
een bestaande. Zo’n voorstel heet in het jargon een JSR (Java Specification Request). Er
wordt dan gestemd of het voorstel aanvaard wordt.
Community Draft Wanneer de JSR aanvaard wordt, begint een groep van experts aan een
eerste versie van de specificatie. Deze wordt nagekeken door de andere leden van de JCP
community die feedback geven. Uiteindelijk wordt er gestemd over deze versie van de
specificatie.
2.5 Java Community Process
20
Public Draft en Final Release De specificatie wordt opengesteld voor het grote publiek. Iedereen kan ze bekijken en er feedback over terugsturen naar de makers van de specificatie.
Hiermee rekening houdend, wordt er een definitieve versie van de specificatie gemaakt die
voor een laatste keer onderworpen wordt aan een stemming. Na een positieve stemming
is de specificatie een nieuwe Java standaard.
Bij het opstellen en de uitwerking van de API werd gebruik gemaakt van een vereenvoudigde en
ingekorte versie van dit proces.
DE API SPECIFICATIE
21
Hoofdstuk 3
De API specificatie
De bedoeling van deze thesis is het beschikbaar maken van systeem resources in Java, opdat
applicaties hiervan gebruik kunnen maken om zichzelf aan te passen aan de beschikbaarheid van
bepaalde resources. We hebben een API gedefinieerd die dit mogelijk maakt. De API specificatie moet geı̈mplementeerd worden op ieder platform waarop we hem wensen te gebruiken. De
implementatie zal dus platformspecifiek zijn. Vanuit het standpunt van de applicatieprogrammeur echter, zal code die gebruik maakt van de API volledig platformonafhankelijk zijn. Alle
platformspecifieke code zit verborgen in de implementatie. De API zelf is geschreven in Java en
ziet er dus op alle platformen hetzelfde uit.
Naast het beschikbaar maken van resources is er een onderdeel van de API dat instaat voor
monitoring. Dit is een framework dat event-gebaseerd is. De gebruiker kan beslissen welke
resource hij wil laten monitoren en wanneer hij op de hoogte gebracht wil worden van een
toestandswijziging van de resource d.m.v. een event.
Het is belangrijk op te merken dat deze API enkel monitoring 1 toelaat en geen driving 2 . De
toegang tot de resources is bijgevolg read-only, het is mogelijk om met behulp van deze API de
eigenschappen van de beschikbare resources te raadplegen maar niet om ze ook te wijzigen.
Doelstellingen De doelstellingen die we in gedachten hielden bij het definiëren van de API
zijn dat de API o.a. de volgende eigenschappen heeft:
1
2
Het continu bevragen van een bepaalde eigenschap
Het aansturen van hardware
DE API SPECIFICATIE
22
Systeem resources beschikbaar op twee manieren Het opvragen moet kunnen gebeuren
via een request-response model (figuur 3.1a) en via een event model (figuur 3.1b).
userprogram
resource
getInformation()
userprogram
monitor service
register()
information
resourceHasChanged()
(a)
(b)
Figuur 3.1: (a) Request-response model, (b) Event model
OSGi compatibel Het is in de eerste plaats de bedoeling dat de API kan gebruikt worden
in een OSGi omgeving. Hij moet zonder wijzigingen ook gebruikt kunnen worden in een
gewone J2SE of J2ME applicatie.
Uitbreidbaar De API moet voldoende generieke klassen of interfaces bevatten die kunnen dienen als beginpunt voor verdere uitbreiding. Bovendien is het wenselijk dat het monitoren
zo algemeen mogelijk is, zodat dit kan gebeuren onafhankelijk van welke resource er precies
gemonitored wordt.
Gemakkelijk in gebruik Het bevragen van resources moet eenvoudig zijn. Het moet mogelijk
zijn met een beperkt aantal methode-aanroepen en de klassen, interfaces en methoden
moeten voor de hand liggende namen hebben. We willen er ook voor zorgen dat alle
courante resources zoals geheugen of netwerkbandbreedte standaard voorzien zijn in de
API.
In de volgende delen van dit hoofdstuk wordt besproken wat de structuur van de API is, waarom
deze zo is en hoe men de API kan gebruiken.
3.1 Resources API
3.1
23
Resources API
Het package dat de resources bevat heet resources. Het is opgebouwd uit een structuur van
resources en een factory-klasse om de resources te creëren. De gedefinieerde resources zijn
allemaal interfaces en de eigenlijke implementaties zijn verborgen voor de gebruiker.
3.1.1
Resources
Resource
De basisinterface Resource is de wortel van de boom die alle resources beschrijft, zie figuur 3.2.
Alle andere resources zijn een uitbreiding van Resource of van een andere afgeleide interface.
«interface»
Resource
+getName()
+getVendor()
+getVersion()
+getProperty(in name)
+getProperties()
«interface»
StaticResource
«interface»
Display
+getSize()
+getColorDepth()
+isGraphical()
«interface»
DynamicResource
+getTotalCapacity()
+getAvailableCapacity()
+getUsage()
«interface»
Keyboard
+hasNavigationInput()
+hasNumericalInput()
+hasTextInput()
«interface»
Memory
+isReadOnly()
+isVolatile()
«interface»
CPU
+getNumberOfProcessors()
«interface»
NetworkConnection
+isConnected()
«interface»
Power
+isBatteryPowered()
«interface»
PointingDevice
+getNumberOfButtons()
«interface»
Storage
+isRemovable()
Figuur 3.2: De hiërarchie van de resources
Deze paragraaf geeft een algemeen overzicht van de API, voor een gedetailleerde en uitgebreide
specificatie verwijzen we u graag door naar de javadoc-pagina’s te vinden op de CD-ROM.
Resource definieert enkele standaard methoden zoals
• public String getName()
3.1 Resources API
24
• public String getVendor()
• public String getVersion()
• public String getProperty(String key)
• public Properties getProperties()
StaticResource
Sommige resources zijn enkel statisch en wijzigen niet of nauwelijks over de tijd. Er valt te denken
aan de eigenschappen van een monitor of invoerapparaat zoals een toetsenbord. Daartoe is de
interface StaticResource, die Resource uitbreidt, gedefinieerd. Enkele belangrijke resources
zijn standaard voorzien:
• Display
• Keyboard
• PointingDevice
De interface StaticResource biedt geen extra algemene methoden aan en fungeert als een
tagging-interface. Dit wil zeggen dat deze alle statische resources onder zich groepeert, dit om
een duidelijk onderscheid te kunnen maken met de dynamische resources.
DynamicResource
Andere resources hebben een veel meer dynamisch karakter en zeer snel wijzigende eigenschappen
en hebben een bepaald gebruik. Om hieraan tegemoet te komen is de interface DynamicResource
gedefinieerd. Zo’n dynamische resource zou bv. een processor of geheugen kunnen representeren.
De eigenschappen die typisch belangrijk zijn bij zo’n resource zijn de mogelijke capaciteit en
het huidige gebruik ervan. Het is dus belangrijk dat deze eigenschappen op een eenvoudige en
uniforme manier kunnen opgevraagd worden via een vaste set methoden:
• public long getAvailableCapacity()
• public long getTotalCapacity()
• public double getUsage()
3.1 Resources API
25
getAvailableCapacity() en getTotalCapacity() geven de absolute waarden terug, dit waar
getUsage() een procentuele weergave van het resourcegebruik teruggeeft. De methoden die de
capaciteit opvragen geven een long terug. Dit werd zo gekozen omdat bijvoorbeeld de capaciteit
van de meeste moderne harde schijven in bytes al lang niet meer kan voorgesteld worden met
een 32-bits int. De maximaal voorstelbare waarde is met een int maar 2 GiB.
Uiteraard is het belangrijk om een aantal veel voorkomende dynamische resources standaard
te voorzien. De meest voor de hand liggende zijn natuurlijk de processor en het geheugen.
Aangezien deze API zich vooral toespitst op draagbare devices is ook de capaciteit van de
batterij en de eventuele netwerkverbinding belangrijk.
De standaard voorziene interfaces zijn:
• CPU
• Memory
– Storage
• NetworkConnection
• Power
Zoals te zien in deze opsomming heeft Memory ook nog een subinterface Storage. Deze extra
interface is toegevoegd om een onderscheid te kunnen maken tussen de verschillende types intern
en extern geheugen zoals daar zijn RAM, ROM, harde schijven . . .
Op de meeste platformen komt Memory overeen met volatiel intern geheugen en Storage met
niet-volatiel, al dan niet extern, geheugen. Het onderscheid is echter niet altijd zo eenvoudig.
Zo bestaan er PDA’s waarbij het RAM-geheugen bewaard blijft bij het uitschakelen en enkel
gewist wordt door een harde reset. In zo’n situaties is het aan de fabrikant om te beslissen of
het geheugen onder Memory of Storage moet geplaatst worden.
3.1.2
Factorymodel
SystemResourceFactory
De hiërarchie van resources is opgebouwd uit interfaces, dit opdat de gebruiker niet afhankelijk
zou worden van één bepaalde implementatie. De eigenlijke implementatie van die interfaces is
3.1 Resources API
26
bovendien verborgen voor de gebruikers. Het moet uiteraard wel mogelijk zijn om instanties van
deze klassen te creëren.
Het model dat dit alles toelaat is de Factory. De klasse SystemResourceFactory representeert
de Factory van deze API (figuur 3.3). Deze klasse laat toe instanties te creëren van klassen die
de resource-interfaces implementeren. Daartoe zijn er een aantal statische methoden voorzien
zoals
• public static Memory getRAM()
• public static CPU getCPU()
• public static Keyboard getKeyboard()
• ...
Meer details zijn terug te vinden in de javadoc-pagina’s.
SystemResourceFactory
+getCPU() : CPU
+getDisplay() : Display
+getKeyboard() : Keyboard
+getNetworkConnection(in name : String) : NetworkConnection
+getNetworkConnectionNames() : String[]
+getPointingDevice() : PointingDevice
+getPower() : Power
+getRAM() : Memory
+getROM() : Storage
+getStorage(in name : String) : Storage
+getStorageNames() : String[]
+getVirtualMachineMemory() : Memory
Figuur 3.3: De factoryklasse SystemResourceFactory
Via deze methoden kan de gebruiker alle courante resources op een eenvoudige en gecentraliseerde
manier opvragen.
Excepties
Omdat er soms weleens dingen kunnen mislopen worden er enkele excepties gedefinieerd. Ze
zijn afgeleid van een gemeenschappelijke klasse ResourceException. Wanneer een resource
opgevraagd wordt die niet bestaat op het apparaat in kwestie, wordt er een ResourceNotFoundException opgeworpen. Dat kan bijvoorbeeld gebeuren wanneer de methode getDisplay()
3.2 Monitoring API
27
aangeroepen wordt op een apparaat zonder scherm. Een andere mogelijkheid is dat de gevraagde
resource misschien wel bestaat, maar om de ene of de andere reden niet ondersteund wordt
door de implementatie van de API. In dat geval wordt een ResourceNotSupportedException
opgeworpen.
3.2
Monitoring API
Het toegankelijk maken van resources is één zaak, maar dat alleen is niet voldoende. Er is nog
een model nodig dat toelaat dat je automatisch op de hoogte gebracht wordt van wijzigingen
in de resources. Bijvoorbeeld een toenemend of afnemend gebruik, of gewoon het beschikbaar
worden van een resource. Dit is waar de monitor komt bij kijken.
Een monitor is een klasse die een bepaalde resource zal observeren. Het is dus niet verwonderlijk
dat een monitor een Resource als argument heeft bij de constructor. Aan de monitor kan
dan gevraagd worden of er een wijziging is opgetreden bij de resource. Als deze wijziging
belangrijk genoeg is zal een event gegenereerd worden. Om dit alles te automatiseren is er een
service-interface gedefinieerd. Deze interface en de monitorklassen vormen samen het package
resources.util.monitor.
3.2.1
Resourcemonitors
Er zijn 3 belangrijke types basisresources nl. Resource, StaticResource en DynamicResource. Aangezien StaticResource eigenlijk enkel fungeert als tagging-interface zijn er maar 2
belangrijke types monitors nl. ResourceMonitor en DynamicResourceMonitor. Het zou de
dingen enkel maar nutteloos complexer maken om ook een StaticResourceMonitor te creëren
aangezien deze geen extra voordelen of restricties met zich meebrengt.
Strikt genomen zou het niet nodig zijn om een onderscheid te maken tussen deze monitors, maar
het wel doen brengt enkele interessante voordelen met zich mee. De gewone resourcemonitor is
immers vooral bedoeld om de statische eigenschappen van resources te monitoren. Dit betekent
eventuele wijzigingen in de properties, bv. de resolutie van een display. Het zijn eigenschappen
die kunnen veranderen maar dit niet vaak doen. Het is belangrijk op te merken dat elke resource,
ook een dynamische, altijd een aantal statische eigenschappen zal hebben. De dynamische
monitor daarentegen is gericht op het observeren van zeer snel wijzigende resources. Doorgaans
heeft het melden van wijzigingen van deze resources een veel hogere prioriteit. Dankzij het
3.2 Monitoring API
28
onderscheid wordt het dan ook een stuk eenvoudiger om met die verschillende noden om te
gaan. Het voorkomt ook dat men de dynamische eigenschappen van een statische resource zou
proberen te monitoren.
Een dynamische resourcemonitor is uiteraard ook gewoon een resourcemonitor en dus wordt
DynamicResourceMonitor afgeleid van ResourceMonitor. Er zijn standaard een aantal alge-
mene monitors voorzien, zoals te zien in figuur 3.4.
ResourceMonitor
«interface»
MonitorService
+addMonitor(in monitor : ResourceMonitor)
+removeMonitor(in monitor : ResourceMonitor)
*
+minimumInterval
+priority
#resource
+monitor()
*
*
«interface»
ResourceListener
+eventOccurred(in event : ResourceEvent)
«implementation class»
MonitorServiceImplementation
ResourceEvent
+source
+message
+data
1
PropertyChangeMonitor
DynamicResourceMonitor
+property
UsageThresholdMonitor
CapacityThresholdMonitor
UsageChangeMonitor
CapacityChangeMonitor
+threshold
+threshold
+minChange
+minChange
Figuur 3.4: De hiërarchie van de monitors
ResourceMonitor en DynamicResourceMonitor zijn 2 abstracte klassen. Ze kunnen dus niet
geı̈nstantieerd worden. De implementatie dient door de gebruiker vervolledigd te worden. Er
is één abstracte methode: public abstract void monitor(). Dit is de methode die moet
opgeroepen worden om na te gaan of er wijzigingen in de resource zijn of niet. Dit heeft als
doel de monitors zo generiek, maar vooral zo veelzijdig mogelijk te maken. Deze werkwijze
laat de gebruiker immers toe om zelf te definiëren wat als wijziging wordt beschouwd. Voor de
ene toepassing zijn wijzigingen in het gebruik van minder dan 15 % misschien niet belangrijk,
waar voor anderen een wijziging van 1 % al belangrijk is. Ook wat betreft de efficiëntie is
dit een belangrijke eigenschap. Er moet immers enkel een event gegenereerd worden wanneer
dit echt nodig is. Concreet wordt er dus binnen de monitor()-methode beslist wanneer de
fireEvent()-methode wordt aangeroepen. Deze aanpak is zeer gelijkaardig aan het implemen-
teren van de service() methode van een servlet in een afgeleide klasse van de abstracte klasse
3.2 Monitoring API
29
GenericServlet, of van de doGet() methode in een HttpServlet 3 .
Events en listeners
Het monitoren is een event-gebaseerd systeem. Het is dus nodig om een event en een listener te
voorzien. Deze zijn terug te vinden onder de namen ResourceEvent en ResourceListener.
Een resource-event bevat een verwijzing naar de event-genererende klasse en kan ook voorzien
worden van een extra boodschap of waarde, zoals het gebruik op dat moment. De bijhorende
listener-interface voorziet een methode public void eventOccurred(ResourceEvent e) die
zal aangeroepen worden bij een event.
Voorgedefinieerde monitors
Om tegemoet te komen aan de gebruikers zijn er een aantal veelgebruikte en belangrijke monitors
voorzien.
UsageChangeMonitor en CapacityChangeMonitor zullen bij elke voldoende grote wijziging
een event genereren. Wat als voldoende grote wijziging beschouwd wordt, is een attribuut
dat kan ingesteld worden.
UsageThresholdMonitor en CapacityThresholdMonitor zullen een event genereren wan-
neer een bepaalde drempelwaarde van het gebruik overschreden wordt. Ook hier is de
drempel een aanpasbaar attribuut.
PropertyChangeMonitor zal een event genereren wanneer een resource-property wijzigt.
Zoals blijkt uit de opsomming zijn er twee types Change- en ThresholdMonitors. Het enige
verschil is dat de UsageMonitor een procentuele waarde zal observeren, en de CapacityMonitor de absolute waarde. Deze laatste laat dus toe om heel nauwkeurig en zonder eventuele
afrondingsfouten te werken. Maar deze vraagt dan ook iets meer accounting van de gebruiker
zelf.
3.2.2
Monitorservice
Het is uiteraard niet handig om telkens zelf de monitor()-methode aan te roepen. Daarom
werd er een interface MonitorService gecreëerd. Een implementatie van deze service zal op
3
Meer over servlets op http://java.sun.com/products/servlet/docs.html
3.2 Monitoring API
30
geregelde tijdstippen de monitor() methode aanroepen. Monitors kunnen toegevoegd en verwijderd worden. Van zodra een monitor toegevoegd wordt begint het monitorproces, tot hij
weer verwijderd wordt.
Er kan ook een prioriteit ingesteld worden opdat, indien dat nodig zou blijken, belangrijkere
monitors voorrang zouden krijgen op de rest. Om een vloed aan gegenereerde events te voorkomen kan bij een monitor een tijdsinterval ingesteld worden waarbinnen maximaal één event
kan gegenereerd worden. Dit resultaat wordt verkregen door de service de monitor()-methode
slechts één keer per interval te laten aanroepen. Eventuele wijzigingen in de resource die weer
ongedaan gemaakt werden door tegenovergestelde wijzigingen binnen dit interval worden dus
niet gedetecteerd, en bijgevolg wordt er ook geen event gegenereerd. Het belangrijkste voordeel
aan deze manier van werken is dat eventuele events binnen het interval niet hoeven gebufferd te
worden, en er ook geen events gegenereerd worden die op het moment van ontvangst vals lijken
te zijn.
Een aandachtspunt voor de programmeur: het is belangrijk te weten dat de voorgedefinieerde
monitorklassen geen voorzieningen bieden om randgevallen op te vangen. Hiermee wordt bedoeld
dat wanneer een gemonitorde eigenschap schommelt rond de drempel van een thresholdmonitor
er voortdurend events zullen gegenereerd worden, terwijl dat misschien niet gewenst is. Zo kan
een thresholdmonitor, die een event genereert telkens het geheugengebruik de grens van 90 %
overschrijdt, er toe leiden dat een maximaal aantal events gegenereerd zal worden indien het
geheugengebruik ook effectief rond de 90 % schommelt. Dit kan belangrijke gevolgen hebben
indien de listener van deze monitor reken- of geheugenintensieve operaties zou starten. Er
moet immers voor gezorgd worden dat het afhandelen van events in de listener een kortstondige
operatie is, opdat de monitor niet geblokkeerd raakt.
Om randsituaties zoals dit drempelvoorbeeld te voorkomen moeten de nodige voorzieningen
genomen worden in de listener, of reeds in de monitor()-methode van de desbetreffende monitor.
Dit kan door overerving van een bestaande monitor en het overriden van de methode, of door een
eigen aangepaste monitor te schrijven die geen overvloed van events genereert bij het schommelen
rond een drempelwaarde.
3.3 Gebruik van de API
31
Waarom monitors?
Men zou zich kunnen afvragen waarom de monitorklassen nodig zijn. Hetzelfde zou bereikt kunnen worden met enkel een monitorservice en listeners. De monitorservice zou dan voortdurend
events genereren bij iedere verandering van een resource en de listeners vangen al deze events
op. In dit scenario moeten de listeners dus zelf maar beslissen of een event voor hen belangrijk
is of niet. Het nadeel hiervan is dus dat de monitorlogica (beslissen welke events belangrijk zijn)
terechtkomt tussen de actielogica die zegt wat er moet gebeuren als er daadwerkelijk op een
belangrijk event moet gereageerd worden.
Onze oplossing hiervoor is om de logica die beslist of een event belangrijk is in een aparte
monitorklasse onder te brengen. In de listeners staat nu enkel wat echt belangrijk is, nl. wat
er moet gebeuren als reactie op een event. Wanneer de listener een event ontvangt van een
monitor, weet die immers al dat het om een belangrijke wijziging gaat die om reactie vraagt,
omdat dit zo beslist werd door de monitor. Naast het feit dat dit overzichtelijker is, heeft dit
nog enkele voordelen. Er worden enkel events gegenereerd wanneer het echt nodig is. Hierdoor
wordt de voortdurende creatie van kort levende eventobjecten wat beperkt, wat de efficiëntie ten
goede komt. Voor de programmeur is het ook voordelig, want voor veel voorkomende soorten
monitoring moet hij niet eens meer de monitorlogica schrijven. Die zit al in de voorgedefinieerde
monitorklassen.
Ten slotte kan ook opgemerkt worden dat dit monitormodel algemeen genoeg is om ook voor
andere doeleinden dan hardwaremonitoring gebruikt te worden. Het monitoren bestaat erin op
geregelde tijdstippen de methode monitor() te laten aanroepen. Wat in die methode staat kan
vrij gekozen worden en hoeft dus in principe niks te maken te hebben met resources. Uiteraard
is het monitoren van hardwareresources wel het hoofddoel.
3.3
Gebruik van de API
Er zijn twee belangrijke toepassingen van de API. Hij kan gewoon gebruikt worden als een
pure resource monitor die eventueel kan gebruikt worden om een waarschuwing te geven bij het
overschrijden van een drempelwaarde of om aan load balancing te doen. Een andere toepassing,
die veel krachtiger is, is adaptieve software. De software past zichzelf aan zijn omgeving aan
zonder expliciete menselijke interventie. Men kan dit op twee manieren interpreteren. Ofwel
3.3 Gebruik van de API
32
blijft de software op dezelfde plaats en verandert de omgeving, ofwel verplaatst de software zich
waardoor uiteraard ook de omgeving zal veranderen.
Men kan vele toepassingen bedenken van adaptieve software. Een voorbeeld is een browser
die alleen de tekst downloadt maar niet alle multimediale toeters en bellen, als er te weinig
bandbreedte voorhanden is. Een programma dat zijn grafische interface zelf aanpast aan de
beschikbare schermruimte is een ander voorbeeld. In het ideale geval zou een zelfde programma
dan kunnen draaien op een 21 inch scherm, maar ook op het kleine schermpje van een GSM.
Verdere toepassingen kunnen zijn: een programma dat zware berekeningen en grafisch geweld
achterwege laat wanneer de batterij bijna leeg is, videostromen die overschakelen naar lagere
resolutie of framerate bij kleinere bandbreedte . . .
De volgende twee delen tonen aan de hand van enkele voorbeeldjes hoe de API gebruikt kan
worden.
3.3.1
Resources API
Met dit onderdeel van de API kan een applicatie nodige informatie over de hardwareomgeving
te weten komen. Dit zal vooral gebruikt kunnen worden in programma’s die verplaatst worden
naar een ander apparaat. Op basis van de opgevraagde informatie kan een programma zichzelf
op de ene of de andere manier configureren om optimaal te draaien gegeven de beschikbare
resources.
Het toegangspunt tot de resources is de klasse SystemResourceFactory. De statische methoden
van deze klasse geven objecten terug die de resources voorstellen. Dit voorbeeld toont hoe we
het geheugen beschikbaar tot de JVM kunnen opvragen.
Memory jvmMem = SystemResourceFactory.getVirtualMachineMemory();
Indien een bepaalde resource niet beschikbaar is op het gebruikte platform, wordt bij de creatie
van die resource in de SystemResourceFactory een ResourceNotFoundException opgeworpen. De methoden getCPU(), getPower(), getRAM() en getVirtualMachineMemory() doen
dit echter niet aangezien deze minimumvereisten zijn voor het CDC/Foundation Profile. Een
typische situatie waar een exception zal opgeworpen worden is een apparaat zonder scherm.
Wanneer het voor de implementatie onmogelijk is om de gevraagde informatie te verschaffen,
wordt er een ResourceNotSupportedException opgeworpen. Het kan zijn dat die resource
wel bestaat, maar het is onmogelijk er iets over te weten te komen.
3.3 Gebruik van de API
33
try {
Display display = SystemResourceFactory.getDisplay();
...
} catch (ResourceNotFoundException e) {
System.err.println("This device has no display.");
} catch (ResourceNotSupportedException e) {
System.err.println("This device may or may not have a display, but we
cannot get information about the display.");
}
Wanneer er geen exception opgeworpen is, heeft het teruggegeven object verschillende methoden die toegang geven tot informatie over de resource in kwestie. De waarden teruggegeven
door deze methoden zijn altijd de meest recente. Het resource-object moet dus maar één keer
opgevraagd worden bij de SystemResourceFactory en kan voor de rest van het programma
gebruikt worden. De totale capaciteit en het aantal bytes in het geheugen dat nog beschikbaar
is tot de virtuele machine, kan eenvoudig opgevraagd worden.
Memory jvmMem = SystemResourceFactory.getVirtualMachineMemory();
long total = jvmMem.getTotalCapacity();
long available = jvmMem.getAvailableCapacity();
Alle resource types hebben ook (quasi-)statische eigenschappen die kunnen opgevraagd worden.
Ze kunnen allemaal tegelijk verkregen worden met de methode getProperties(). Deze geeft
een object terug dat alle eigenschappen bevat.
Properties properties = jvmMem.getProperties();
String[] keys = properties.getKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
System.out.println(key + ": " + properties.getProperty(key));
}
Deze klasse Properties heet voluit resources.util.Properties en is niet de java.util.Properties uit de standaard bibliotheek van Java. Deze laatste bevat te veel methoden die
in deze context niet nodig zijn. Daarom is er een aparte en zeer compacte Properties-klasse
voorzien.
3.3 Gebruik van de API
34
Eén enkele eigenschap kan ook opgevraagd worden met de methode getProperty(String
key).
Memory rom;
try {
rom = SystemResourceFactory.getROM();
String readOnly = rom.getProperty("readOnly");
if (readOnly.equals("true")) {
System.out.println("ROM is read-only");
}
} catch (ResourceNotFoundException e) {
} catch (ResourceNotSupportedException e) {
}
3.3.2
Monitoring API
Dit deel van de API biedt een raamwerk om resources te monitoren. De werkwijze om een
resource te monitoren bestaat uit drie stappen die geı̈llustreerd worden in figuur 3.5:
1. Maak een instantie van een klasse die afgeleid is van de abstracte klasse ResourceMonitor.
2. Voeg listeners toe aan deze monitor.
3. Voeg deze monitor toe aan de service MonitorService die ervoor zorgt dat het monitoren
begint.
Een monitor aanmaken
Een monitor bevat alle gegevens om een resource te monitoren. Alle monitors zijn afgeleiden
van de abstracte klasse ResourceMonitor of van een abstracte subklasse DynamicResourceMonitor. Ze zijn abstract omdat één methode nog niet geı̈mplementeerd is, nl. monitor().
In deze methode moet geschreven worden wat er zal gebeuren tijdens één monitorcyclus. De
programmeur heeft twee methoden ter beschikking die gebruikt moeten worden in de methode
monitor: een methode om toegang te krijgen tot de resource die gemonitord moet worden,
getResource() (of getDynamicResource() voor dynamische resources), en een methode die
3.3 Gebruik van de API
35
userprogram
:MonitorService
new
monitor:ResourceMonitor
1.
new
2.
aListener:ResourceListener
addListener(aListener)
addMonitor(monitor)
3.
loop
if
monitor()
eventOccurred()
Figuur 3.5: Gebruik van het monitorgedeelte van de API
moet aangeroepen worden wanneer er reden is om een event te genereren, fireEvent(). Dit
alles maakt het mogelijk om zelf monitors te definiëren en dit voor alle mogelijke resourcetypes.
Het volgende voorbeeld toont een implementatie van een door de gebruiker gemaakte monitor.
Deze eenvoudige monitor vuurt events af wanneer het gebruik van de dynamische resource in
een bepaald interval komt of dit interval verlaat.
import resources.DynamicResource;
import resources.util.monitor.DynamicResourceMonitor;
public class IntervalMonitor extends DynamicResourceMonitor {
private double from, to;
3.3 Gebruik van de API
36
private double previous;
public IntervalMonitor(DynamicResource res, double from, double to) {
super(res);
this.from = from;
this.to = to;
previous = res.getUsage();
}
public void monitor() {
double current = getDynamicResource().getUsage();
if ((current >= from && current <= to) && (previous < from ||
previous > to)) {
fireEvent("in", new Double(current));
} else if ((previous >= from && previous <= to) && (current <
from || current > to)) {
fireEvent("out", new Double(current));
}
previous = current;
}
}
In de plaats van deze klassen zelf te schrijven kan een programmeur het zichzelf ook gemakkelijk
maken door klassen te gebruiken die de monitor-methode al implementeren en die voorzien zijn
in de API. Een voorbeeld hiervan is UsageThresholdMonitor, een monitor die events stuurt
wanneer het gebruik van een dynamische resource een bepaalde drempelwaarde overschrijdt.
Het volgende voorbeeld maakt zo’n monitor aan. Hij zal het virtuele-machinegeheugen monitoren en events genereren wanneer het geheugengebruik 90 % overschrijdt.
Memory jvmMem = SystemResourceFactory.getVirtualMachineMemory();
UsageThresholdMonitor monitor = new UsageThresholdMonitor(jvmMem, 90);
De monitors hebben nog andere attributen zoals de prioriteit en het minimum interval tussen
twee monitorcycli. Al deze attributen hebben een defaultwaarde die, indien gewenst, expliciet
kan gewijzigd worden. Voor meer informatie hierover wordt verwezen naar de API specificatie
op de cd-rom. Indien deze defaultwaarden voldoen, is bovenstaande alles wat nodig is om een
3.3 Gebruik van de API
37
monitor te creëren.
Listeners toevoegen aan de monitor
Listeners zijn klassen die de events ontvangen die gegenereerd worden door een monitor en een actie ondernemen wanneer ze een event ontvangen. Ze moeten de interface ResourceListener implementeren. Dit bestaat erin dat de listenerklasse een publieke methode eventOccurred(ResourceEvent) moet hebben waarin staat wat er moet gebeuren bij het ontvangen van een event.
Dit is de plaats waar de actie zich afspeelt. Het is hier dat software adaptief kan gemaakt worden
door gepast te reageren op wijzigingen in de omgeving.
Aansluitend bij het vorige voorbeeld maken we een listener die telkens wanneer hij een event
ontvangt gewoon een boodschap op het scherm toont.
ResourceListener listener = new ResourceListener() {
public void eventOccurred(ResourceEvent e) {
System.out.println("Threshold crossed.");
System.out.println("Threshold is " + ((UsageThresholdMonitor)e.
getMonitor()).getThreshold());
System.out.println("Current value is " + (Double)e.getData());
System.out.println("Message is " + e.getMessage());
}
};
monitor.addListener(listener);
Merk op dat een event drie gegevens bevat: de monitor die het event verstuurd heeft, een boodschap en een Object, typisch een Double of Integer, dat wat extra informatie kan meegeven,
zoals de gemeten waarde die het event veroorzaakte.
De monitor toevoegen aan de service
Om te beginnen monitoren moet de aangemaakte monitor alleen nog toegevoegd worden aan
de service MonitorService. In een OSGi-omgeving zal dit daadwerkelijk een service zijn die
MonitorService als interface heeft.
De service zal volledig het monitoren verzorgen door
herhaaldelijk de monitor-methode aan te roepen en zal het beheer van alle monitors op zich
nemen.
We voegen de monitor uit het voorbeeld toe aan de service.
3.3 Gebruik van de API
38
//In OSGi bundel eerst het service-object opvragen via de BundleContext
ctxt
ServiceReference sref = ctxt.getServiceReference("resources.util.monitor.
MonitorService");
MonitorService service = (MonitorService) ctxt.getService(sref);
service.addMonitor(monitor);
In een gewone J2ME of J2SE omgeving, zonder het OSGi-framework, kan de service als volgt
verkregen worden.
MonitorService service = MonitorServiceFactory.getMonitorService();
service.addMonitor(monitor);
Hier eindigt het werk van de programmeur. Het monitoren is gestart, events zullen worden
verstuurd en het programma zal acties ondernemen bij het ontvangen van events. Het enige wat
nog moet gebeuren is de monitors terug verwijderen uit de service wanneer ze niet meer nodig
zijn. Daarvoor bestaat er een methode removeMonitor().
3.4 Besluit
3.4
39
Besluit
De gespecificeerde API maakt het mogelijk toegang te krijgen tot alle courante systeem resources
in Java, meer bepaald in een OSGi-omgeving. Bovendien biedt het een framework aan om aan
resource monitoring te doen. De API is uitbreidbaar want nieuwe resources kunnen afgeleid
worden van generieke resource-interfaces. Ook kan de gebruiker zelf nieuwe monitors aanmaken
door af te leiden van abstracte monitorklassen.
Deze API maakt het mogelijk om op een relatief eenvoudige en platformonafhankelijke wijze
adaptieve software te ontwikkelen.
DE IMPLEMENTATIE
40
Hoofdstuk 4
De implementatie
Na het opstellen van de API dient deze uiteraard geı̈mplementeerd te worden. Een geslaagde
implementatie zal aan alle eisen van de specificatie voldoen en ook geen beperkingen opleggen
die niet expliciet in de specificatie opgenomen zijn.
Deze specifieke implementatie zal zich richten tot het platform TabletPC + WindowsXP Tablet
Edition [17]. Wegens de sterke gelijkenis van het doelplatform en de gemiddelde hedendaagse PC,
zal deze implementatie zonder aanpassingen, ook werken op een gelijkaardig desktopplatform.
Een belangrijk aandachtspunt is, dat de implementatie zonder noemenswaardige problemen moet
kunnen uitgebreid worden om meerdere doelplatformen te ondersteunen.
In een eerste paragraaf zal op de algemene structuur van de implementatie van de resources
ingegaan worden, en later zal aan de hand van een voorbeeld, meer gedetailleerd, de concrete
implementatie van een resource besproken worden.
Naast de eigenlijke resources definieert de API ook nog een monitor-framework. Uiteraard dient
ook dit geı̈mplementeerd te worden. Dit deel van de API zal geen native code bevatten, en is
bijgevolg zonder enig probleem overdraagbaar naar andere platformen.
4.1
Algemene Structuur
De structuur van de implementatie is reeds voor een groot deel door de specificatie bepaald,
maar er blijft nog een zekere vrijheid over. De mogelijke keuzes en hun motivatie komen hier
aan bod.
4.1 Algemene Structuur
4.1.1
41
Scheiding tussen specificatie en implementatie
De specificatie definieert hoe de publieke packages en klassen zich zullen gedragen. Dit is een
stabiel geheel dat niet meer kan en mag wijzigen. Het is daarom aangewezen om er ook tijdens
de implementatie voor te zorgen dat dit publieke deel stabiel blijft en niet, of zo weinig mogelijk
dient gewijzigd te worden. Dit wordt zeker belangrijker naarmate men meerdere platformen wil
ondersteunen met één enkele implementatie. Uiteraard kunnen eventuele toekomstige releases
van deze specificatie wel nog wijzigingen of uitbreidingen toevoegen. Verschillende implementaties moeten zich echter houden aan de specificaties van de API. Het is daarom ook wenselijk
dat dit in de code naar voor komt. Aangezien de specificatie voor het overgrote deel uit interfaces bestaat, en wegens het gebruikte factory-designpattern lijkt een gescheiden structuur zelfs
vanzelfsprekend.
Er is voor gekozen om alle implementatie-specifieke klassen in een aparte package-hiërarchie
te plaatsen. De publieke interfaces en klassen, zoals aangeduid in de specificatie zijn bevat
in de resources.* hiërarchie en de toegevoegde implementatie-specifieke klassen zijn in de
be.ugent.ibcn.* hiërarchie1 bevat. Dit laat een optimale scheiding tussen implementatie
en specificatie toe. Het resultaat van deze extra gelaagdheid is dat met minimale moeite de
bestaande implementatie kan vervangen worden door een andere. Bovendien voorkomt het ook
een aantal praktische problemen ivm. de naamgeving van klassen. Het is immers niet nodig om
voor elke resource een nieuwe naam te gaan verzinnen omdat deze al zou ingenomen zijn door
de interface. Dezelfde techniek wordt bv. ook toegepast door Sun in de implementatie van de
eigen Java Runtime en heeft reeds zijn degelijkheid bewezen.
Naast de scheiding tussen de specificatie en de implementatie is er ook nog de scheiding tussen
het platformonafhankelijke en het platformafhankelijke deel van de code. Zoals weergegeven
in figuur 4.1. Ook hier is weer een extra verdeling in lagen doorgevoerd wat toelaat om de
implementatie zo algemeen mogelijk te houden, zoals later zal blijken.
4.1.2
Platformonafhankelijke code
Alle Java-code van de implementatie is platformonafhankelijk. Niet omdat het om Java-code
gaat, maar omdat in deze code geen veronderstellingen gemaakt zijn over het onderliggende
1
Het is in Java de gewoonte om eigen packages te laten beginnen met de omgekeerde domeinnaam van de
producent. De domeinnaam van de vakgroep leek mij hiervoor een goede keuze.
4.2 Implementatie van een Resource: RAM
42
Specificatie
Implementatie platformonafhankelijk
Implementatie platformafhankelijk
Figuur 4.1: De verschillende lagen in de implementatie.
platform. In het package be.ugent.ibcn.resources is voor elke resource die de SystemResourceFactory kan teruggeven een implementatie voorzien. Dit houdt in dat er een klasse bestaat
die de nodige interfaces implementeert en in de nodige native calls voorziet.
4.1.3
Platformafhankelijke code
De platformafhankelijke code bestaat uit een aantal shared libraries die in de nodige methoden
voorzien om de informatie, niet rechtstreeks beschikbaar in Java, aan te leveren. Het is belangrijk
dat ook op dit native niveau de mogelijkheid geboden wordt om te bepalen of een bepaalde
resource ondersteund wordt of niet. Stel dat dit reeds in de Java-code beslist is, dan wordt de
portabiliteit van de code beperkt. Het is immers perfect mogelijk dat op een bepaald platform
bepaalde informatie wel op te vragen is en dat dit op een ander platform niet mogelijk is. Bv.
het opvragen van het cpu-gebruik op TabletPC en PocketPC.
Het ondersteunen van meerdere platformen wordt op deze manier gewoon een kwestie van voorzien in de nodige native libraries.
4.2
Implementatie van een Resource: RAM
In de vorige paragraaf werd een algemene uiteenzetting gegeven over hoe de implementatie
gestructureerd is. Hier volgt nu een meer gedetailleerde uitwerking voor één resource. Het doel
hiervan is een duidelijk beeld te scheppen van de implementatie, het rechtstreekse verband met
de interfaces uit de specificatie en met de eigenlijke hardware.
4.2 Implementatie van een Resource: RAM
43
In de API zijn een aantal resources gespecificeerd zoals de processor, het ramgeheugen, de
opslagmogelijkheden enz. In het eenvoudigste geval is er een één op één relatie tussen enerzijds
de hardware en de in de API gedefiniëerde resources en anderzijds de in de API gedefiniëerde
resources en de implementatieklassen. Een voorbeeld hiervan is de muis, waarvan er doorgaans
één op het apparaat beschikbaar is. Zie figuur 4.2a.
Een meer complex geval hebben we bij het geheugen. Er zijn immers meerdere types van
geheugen zoals het RAM en ROM, maar ook de vaste schijven, schijfstations met verwisselbare
schijven, memory-disks enz. Dit komt ook tot uiting in de hiërarchie van interfaces waar Storage
de interface Memory uitbreidt. Storage wordt op zijn beurt dan weer gebruikt om zowel het
ROM-geheugen als de vaste schrijven voor te stellen. Maar beiden vereisen een verschillende
implementatie. Zie figuur 4.2b.
ROM
RAM
vaste schijf
interface Memory
muis
interface Storage
interface
PointingDevice
implementatie RAM
implementatie ROM
implementatie
PointingDevice
(a)
implementatie schijf
(b)
Figuur 4.2: (a) Het eenvoudigste geval met een één op één relatie, (b) Een meer complexe
structuur van geheugens en storage-devices.
Concreet komt het er op neer dat de vereenvoudiging door de specificatie van de interfaces niet
4.2 Implementatie van een Resource: RAM
44
kan doorgetrokken worden op het niveau van de implementatie. Maar dit is helemaal niet erg.
Conceptueel zullen we deze verschillende resources immers net op dezelfde manier gebruiken.
Indien we de vrije ruimte op een storage-device wensen te kennen, willen we dit device op
dezelfde manier kunnen benaderen onafhankelijk van het specifieke type van het device. Het
zijn immers enkel de interfaces die van nut zijn voor de eindgebruiker van de API. Deze zijn net
zo gedefinieerd zodat er geen onderscheid dient gemaakt te worden.
Om de gedachten te vestigen zal in wat volgt de implementatie van het RAM-geheugen overlopen
en aangevuld worden met de nodige annotaties om het geheel te verduidelijken. Een overzicht
van alle implementatieklassen is te vinden in bijlage D.
4.2.1
Platformonafhankelijke code
Een instantie die het RAM-geheugen representeert kan opgevraagd worden met de methodeoproep getRAM() uit de SystemResourceFactory. Deze methode heeft als return-waarde een
object van het type Memory.
De klasse RAMMemory implementeert de methoden gedefinieerd door de interface Memory, en
indien mogelijk worden deze direct gemapt naar native calls. De implementatie ziet er dan als
volgt uit:
package be.ugent.ibcn.resources;
import resources.ResourceNotSupportedException;
public class RAMMemory extends DynamicResource implements resources.Memory
{
static {
System.loadLibrary("rammemory");
}
Eerst en vooral komen de package-definitie en de klasse-definitie. De klasse RAMMemory breidt
een abstracte klasse DynamicResource uit en implementeert de interface Memory. Analoog aan
de interfaces-hiërarchie in de specificatie is er een abstracte klasse Resource, StaticResource en
DynamicResource voorzien. Dit laat toe om een aantal generieke methoden, gelijk voor alle
interfaces op één enkele plaats te implementeren.
De native library waarvan gebruik gemaakt wordt door deze klasse heet rammemory.dll en
moet geladen worden via het bovenstaande static-blok.2
2
Het is niet nodig om voor- of achtervoegsels mee te geven, de Java Virtual Machine zorgt hier zelf voor
4.2 Implementatie van een Resource: RAM
45
public RAMMemory() throws ResourceNotSupportedException {
super();
if (!isSupported()) {
throw new ResourceNotSupportedException("RAMMemory is not
supported on this platform.");
}
setName("RAMMemory");
}
public native boolean isSupported();
Vervolgens komt de constructor, deze kan een ResourceNotSupportedException opwerpen
indien het platform waar de code wordt op uitgevoerd niet ondersteund wordt. Om te beslissen
of deze Exception dient opgeworpen te worden wordt gebruikt gemaakt van de native methode
isSupported(). Zoals reeds aangegeven in punt 4.1.3 is het belangrijk dat deze beslissing op
het native niveau genomen wordt om de porteerbaarheid van de code te kunnen garanderen.
Tenslotte volgen alle methoden gedefinieerd door de geı̈mplementeerde interfaces:
public native long getAvailableCapacity();
public native long getTotalCapacity();
public native double getUsage();
public native boolean isReadOnly();
public native boolean isVolatile();
}
Ook hier is het belangrijk dat zo veel mogelijk informatie op het native niveau opgevraagd wordt.
Indien men meer dan één platform wil ondersteunen, wordt dit beperkt tot het toevoegen van
de nodige bibliotheken voor dat platform.
De verleiding is immers groot om een methode als isVolatile() steeds true te laten teruggeven,
reeds in de Java-code. Maar er bestaan pda’s waar dit niet altijd het geval is.
4.2.2
Platformafhankelijke code
De native methoden uit de Java-klasse moeten vervolgens ook geprogrammeerd worden. Typisch
gebeurt dit in C of C++, maar theoretisch kan het ook in andere programmeertalen. Zelf heb
naargelang het gebruikte platform. bv. *.dll voor Windows en lib*.so voor Unix.
4.2 Implementatie van een Resource: RAM
46
ik voor C gekozen.
De broncode ziet er dan als volgt uit:
#include <windows.h>
#include "be_ugent_ibcn_resources_RAMMemory.h"
Eerst volgen de vereiste include-statements. Er is de header-file windows.h, nodig om informatie over het geheugen op te vragen. En ook de header-file be ugent ibcn resources RAMMemory.h
die de functie-definities van de native methoden beschrijft. Deze header-file kan automatisch
gegenereerd worden met behulp van de executable ’javah’. Een complete bespreking en tutorial
over de werking en het gebruik van JNI is terug te vinden op de site van Sun [15].
Wat volgt in de source-file is een uitwerking van alle methodes:
JNIEXPORT jboolean JNICALL
Java_be_ugent_ibcn_resources_RAMMemory_isSupported
(JNIEnv * env, jobject obj) {
jboolean result = 1;
return result;
}
Er is de methode die aangeeft of een resource ondersteund is op het platform. Deze doet niets
meer dan het teruggeven van true of false. Het RAM is ondersteund op het doelplatform en
dus wordt er true teruggegeven.
JNIEXPORT jlong JNICALL
Java_be_ugent_ibcn_resources_RAMMemory_getTotalCapacity
(JNIEnv * env, jobject o) {
MEMORYSTATUS memstat;
GlobalMemoryStatus(&memstat);
return memstat.dwTotalPhys;
}
Hetzelfde gebeurt voor alle andere methoden gedefinieerd in de gegenereerde header-file. Bovenstaande methode vraagt de totale hoeveelheid geheugen op en geeft dit resultaat terug.
4.3 Implementatie van de Monitor
4.3
47
Implementatie van de Monitor
Eigenlijk is het monitor-framework niets meer dan een standaard meegeleverde toepassingsapplicatie die gebruik maakt van de nieuwe mogelijkheden, geboden door de geı̈mplementeerde
resources. Bovendien kan het helemaal in Java geschreven worden en is het dus per definitie
overdraagbaar naar andere platformen zonder enige aanpassing.
Alle noodzakelijke klassen voor de Monitor zijn gegroepeerd in het resources.util.monitorpackage. Centraal in dit package staan de interface MonitorService en de factory-klasse
MonitorServiceFactory. Daarnaast zijn een aantal default monitors meegeleverd. Allen met
een eenvoudige vanzelfsprekende implementatie. De code is terug te vinden in appendix I.
4.3.1
MonitorService
Een klasse die wat meer aandacht verdient is de implementatie van de monitorservice. In het
package be.ugent.ibcn.resources.util.monitor is een implementatie van deze interface
voorzien. Deze klasse implementeert de interface Runnable aangezien deze in een onafhankelijk
thread moet kunnen lopen.
Zelf houdt deze klasse een lijst van threads bij die elk een Monitor bevatten. Elk van deze threads
slaapt gedurende een aantal milliseconden, zoals gedefinieerd met de methode setMinimumInterval(
int interval). Bij het wakker worden wordt de monitor()-methode aangeroepen en valt de
tijd opnieuw in slaap voor een aantal milliseconden. Elk van deze threads behoren tot een
ThreadGroup beheert door de implementatie van MonitorService en hun prioriteit wordt in-
gesteld volgens de prioriteit van de monitors. Dit volstaat voor een stand-alone gebruik van de
API.
4.4
Integratie met het OSGi-framework
Tot nu is enkel de implementatie van de API aan bod gekomen, zonder expliciet rekening te
houden met de OSGi-omgeving waarin deze implementatie zal ingebed worden.
4.4 Integratie met het OSGi-framework
4.4.1
48
Bundels
Zoals reeds aan bod gekomen is in het eerste hoofdstuk, werkt het OSGi- framework met bundels
welke eenvoudig kunnen in- en uitgeplugd worden. Aangezien de API en ook de implementatie
in twee delen kan opgesplitst worden, is het ook logisch deze zelfde scheiding door te voeren in
het samenstellen van de bundels. Dit vergroot de vrijheid van de gebruiker en vereenvoudigt
ook het onderhoud van de code. Indien er ondersteuning voor nieuwe platformen toegevoegd
wordt, moet enkel de resources-bundel aangepast worden.
Resources
Een eerste bundel zal alle klassen uit de packages resources, resources.util en
be.ugent.ibcn.resources bevatten. Concreet wil dit zeggen alle packages die gebruik maken
van de JNI-interface.
De Manifest-file van deze bundel zal dus moeten voorzien in een Bundle-NativeCode-header
die alle native libraries vermeld en voor welke platformen deze geschikt zijn. Verder worden
ook de te exporteren packages beschreven. In deze header kunnen meerdere libraries voor
meerdere platformen opgegeven worden. De OSGi-omgeving zal dan zelf beslissen welke de
correcte libraries zijn en deze laden. Dit is waarom het zo belangrijk is dat de Java-klassen en
de native libraries zo goed gescheiden zijn.
Het enige doel van deze bundel is het exporteren van de nodige packages en deze toegankelijk
te maken voor andere bundels die er wensen gebruik van te maken.
Monitor
De bundel die de monitor bevat zal de packages resources.util.monitor en
be.ugent.ibcn.resouces.util.monitor bevatten. Uiteraard maakt deze bundel gebruik van
de resources bevat in de Resources-bundel en zal de packages door deze bundel geëxporteerd
dan ook importeren. Dit gebeurt door middel van de Import-Package-header. Uiteraard zal
deze bundel ook zijn eigen publieke packages exporteren zodat deze kunnen gebruikt worden
door adaptieve software-bundels.
De monitor-bundel is zelf ook een stuk software die een eigen thread opstart waarbij monitors kunnen geregistreerd worden. Daartoe dient er in de Manifest-file van de bundel een
4.5 Problemen en opmerkingen
49
Bundle-Activator-header gedefinieerd te zijn welke verwijst naar de Activator-klasse van de
bundel. De implementatie van deze Activator zal toelaten dat de MonitorService gestart
wordt en dat de monitors kunnen geregistreerd worden.
4.5
4.5.1
Problemen en opmerkingen
Speciale resources
Bij de algemene bespreking over de implementatie van de resources zijn we ervan uitgegaan dat
alle data over een resource rechtstreeks kan opgevraagd worden. Dit is echter niet altijd het
geval. Zo zijn er een aantal resources zoals de processor en de netwerkverbinding waarbij het
gebruik op een bepaald moment in de tijd niet eenduidig te definiëren is. Het gebruik bij dit type
resources wordt gedefinieerd in functie van een (kleine) tijdspanne bv. het aantal verstuurde
bytes per seconde, in het geval van de netwerkverbinding. De verdere beschrijving verloopt aan
de hand van de netwerkverbinding.
Het gaat hier dus eigenlijk om statistische gegevens dewelke niet altijd rechtstreeks toegankelijk
zijn. Dit vereist immers een zekere ondersteuning van het onderliggende platform. Wat vaak
wel beschikbaar is, is het totaal aantal verstuurde bytes sinds het opstarten van de machine.
Daarom vereist de implementatie van deze resources extra inspanning.
De oplossing waarvoor gekozen is, bestaat er in deze resources te implementeren als een Thread.
Bij constructie wordt deze gestart, en van dat moment af zal deze op vaste tijdsintervallen
het totale aantal verwerkte bytes opvragen, en aan de hand van de vorige gemeten waarde een
gemiddeld gebruik per tijdseenheid berekenen. Deze gemiddelde waarde is dan de waarde die
teruggegeven wordt.
4.5.2
Het wiel opnieuw uitvinden
Deze implementatie dient te voldoen aan de eisen gesteld door het J2ME CDC/Foundation
profile. Zoals reeds eerder vermeld, is deze specificatie gebaseerd op de J2SE 1.2 API Specificatie.
Ondertussen heeft de ontwikkeling van het Java-platform niet stilgestaan en is op het moment
van schrijven reeds de J2SE 1.5.0 Beta 1 API Specificatie beschikbaar. Een aantal van de
uitbreidingen van de specificatie blijken ook voor onze Resource API relevant te zijn.
4.5 Problemen en opmerkingen
50
Zo is het sinds versie 1.4 mogelijk om rechtstreeks aan de Runtime het aantal beschikbare
processors op te vragen. Eveneens sinds versie 1.4 is de klasse java.net.NetworkInterface
toegevoegd welke de implementatie van de netwerk-resource aanzienlijk kan vereenvoudigen. En
tenslotte is er ook een klasse java.awt.GraphicsDevice die sinds versie 1.4 alle informatie
aanbiedt vereist door onze API. In vorige versies van de specificatie waren de cruciale methoden
hiervoor nog niet voorzien.
Dat een aantal van de geı̈mplementeerde resources ook rechtstreeks vanuit de JVM zullen beschikbaar worden is echter helemaal geen probleem. Integendeel, indien deze klassen op termijn
ook in de J2ME configuraties zouden beschikbaar worden, vereenvoudigt dit enkel de implementatie. En ook het nut van deze opgestelde API zal niet verdwijnen. Deze API blijft immers een
duidelijk overzicht bieden van de toegankelijke resources en vormt een centraal aanspreekpunt.
Bovendien is er ook nog de krachtige en flexibele monitoring API die zijn nut blijft behouden.
4.5.3
Niet geı̈mplementeerde resources
Er zijn bij het implementeren van de gedefinieerde resources geen noemenswaardige problemen
opgetreden. Eén resource werd niet geı̈mplementeerd, namelijk het ROM. In het geval van de
TabletPC is dit het BIOS. Deze informatie is op dit platform zeer ontoegankelijk en bovendien
heel apparaat-specifiek. Deze resource is op dit platform echter niet zo belangrijk waardoor de
impact van dit gebrek heel beperkt blijft.
Er is ook één resource die niet helemaal voldoet aan de specificatie, de NetworkConnection zal
niet altijd een correct resultaat geven bij een oproep van de methode isConnected(). Strikt
genomen dient deze methode na te gaan of de netwerkverbinding actief is, de implementatie zal
echter aangeven of de interface werkt of niet. Alle andere methoden, zoals het meten van de
bandbreedte, werken naar behoren.
4.5.4
Theorie vs. praktijk
Verder zijn er nog een heleboel zaken die principieel heel mooi zijn, maar de praktijk voldoet
niet altijd aan de eisen gesteld door de theorie. Of het is gewoon niet efficiënt om het op die
manier te doen.
4.5 Problemen en opmerkingen
51
Beperkingen van de OSGi-omgeving
Zoals reeds eerder vermeld biedt de OSGi-omgeving de mogelijkheid om dynamisch de juiste
native libraries te selecteren voor het juiste platform. In de praktijk blijkt deze mogelijkheid
echter nog niet fijnmazig genoeg geı̈mplementeerd te zijn. Momenteel kan er geselecteerd worden
op basis van:
• processor-type
• besturingssysteem
• versienummer van het besturingssysteem
• taal
Wegens de erg specifieke informatie die dient opgevraagd te worden, blijkt deze informatie
niet altijd voldoende. De verscheidenheid in mobiele devices is enorm. Hoewel vaak dezelfde
besturingssystemen teruggevonden worden, hebben deze vaak uitbreidingen, specifiek voor één
type toestel of één bepaald merk. Meestal blijkt nu net in deze uitbreidingen de informatie te
zitten nodig voor onze API. Een voorbeeld hiervan is de iPAQ PocketPC, met een merkspecifieke
API.
De specifieke implementatie voor TabletPC in combinatie met WindowsXP Tablet Edition heeft
als voordeel dat gebruik kan gemaakt worden van de Windows-API die zo goed als helemaal
gelijk is voor alle versies van WindowsXP.
Efficiëntie
Het is natuurlijk heel mooi dat de OSGi-omgeving dynamisch kan beslissen welke native libraries
dienen gebruikt te worden. Maar het is niet erg efficiënt dat een bundel die een tiental platformen
ondersteund, en dus een veelvoud native libraries bevat, zou gebruikt worden op een klein mobiel
toestel met beperkte opslag. In heel veel gevallen zal deze bundel éénmaal in een OSGi-omgeving
geı̈nstalleerd worden. Net zoals je éénmaal kiest welke OSGi-omgeving, en Java Virual Machine
installeert.
Vanuit hetzelfde oogpunt kan het in sommige gevallen beter zijn het aantal native calls te beperken en hier en daar iets op het Java-niveau af te handelen. Dit vormt een kleine beperking op de
automatische porteerbaarheid van de implementatie maar heel waarschijnlijk is het nog altijd
4.5 Problemen en opmerkingen
52
mogelijk een heleboel gelijkaardige platformen te ondersteunen, door enkel de native libraries
aan te passen.
Een reële situatie zou bv. ook kunnen zijn dat de makers van een bepaald apparaat zelf in
een implementatie voorzien. De kans dat deze implementatie meerdere apparaten (van andere
fabrikanten) zal ondersteunen lijkt ook in dat geval behoorlijk klein.
4.6 Besluit
4.6
53
Besluit
Er is gekozen voor een implementatie die duidelijk opgesplitst is in verschillende onderdelen, die
zo porteerbaar mogelijk gehouden zijn. Enkel de native libraries zullen moeten herschreven en
hercompileerd worden om meerdere platformen te ondersteunen. Dit was een bewuste keuze om
een maximale algemeenheid en portabiliteit te garanderen.
Het blijkt echter ook dat dit geen zaligmakende keuze is. Er zijn voldoende argumenten om een
andere weg in te slaan en de implementatie specifieker te maken voor één apparaat of een groep
van apparaten. De TabletPC is echter een voldoende krachtig platform met voldoende schijfen geheugenruimte zodat de efficiëntie een minder bepalende factor is dan op meer beperkte
apparaten. Het is ook een vrij algemeen platform, waardoor het kiezen voor een algemene
implementatie geen probleem vormt. Er is geen juiste of foute keuze, maar het belangrijkste is
dat de implementatie voldoet aan de eisen gesteld door de API.
Het einderesultaat is een concrete implementatie van de opgestelde API die voldoet aan alle
eisen en geen beperkingen oplegt. De implementatie is conform met het J2ME CDC/Foundation
profile waarmee de voorop gestelde eisen vervuld zijn.
TOEPASSING
54
Hoofdstuk 5
Toepassing
Tot nu toe is er een API-specificatie opgesteld die het mogelijk maakt om informatie over de
systeemresources op te vragen en deze automatisch te later monitoren. Met een implementatie
die helemaal OSGi-compatibel is en werkt op een Java platform dat voldoet aan de eisen gesteld
door het CDC/Foundation profile hebben we alle ingrediënten om de applicaties geschetst in
het inleidende hoofdstuk ook echt te verwezenlijken.
Dankzij de Java Virtual Machine kunnen we onze code éénmaal schrijven, éénmaal compileren
en vervolgens overal uitvoeren. De OSGi-omgeving laat ons toe de software heel eenvoudig te
installeren, te upgraden of te verwijderen. En dankzij onze API kunnen we onze software at
runtime aanpassen aan de statische en dynamische eigenschappen van het apparaat.
Bij wijze van demonstratie zijn er een aantal demo-toepassingen ontworpen. In een eerste fase
is er een heel eenvoudige resourcemonitor ontworpen om de implementatie te kunnen te testen.
Daarna is er aan een meer representatieve toepassing gewerkt, namelijk een mediaplayer. Deze
mediaplayer zal zich dynamisch kunnen aanpassen aan de beschikbare processorkracht. Indien
de processor te zwaar belast wordt, wat zou leiden tot een slechte weergave van de video, kan
de grootte van het scherm aangepast worden, of kan er overgeschakeld worden naar een ander
bronbestand.
De grootte van het scherm heeft een invloed daar het herschalen van de media extra rekenkracht
kost. Ook het gebruikte bronbestand kan een invloed hebben naargelang de gebruikte codec, de
compressiegraad van de media en de algemene kwaliteit.
Men kan ook om heel andere redenen rekening houden met het processorgebruik, nl. het extra
stroomverbuik dat een zwaar belaste processer met zich meebrengt. Bij toestellen die met
5.1 Resourcemonitor
55
batterijen werken is dit zeker een must.
Uiteraard zal deze demo-applicatie hogere eisen stellen dan het CDC/Foundation profile waaraan de API-implementatie zich houdt. Dit profiel vereist immers niet eens dat het gebruikte
toestel een monitor heeft. Een videoplayer voor zo’n platform implementeren zou bijgevolg nogal nutteloos zijn. Bovendien vereist het afspelen en decoderen van multimediabestanden een
behoorlijke rekenkracht. Een TabletPC is hierop voorzien, een PDA of GSM echter (nog) niet.
Dit demonstreert ook onmiddellijk dat het geen enkel probleem is om deze API op een ruim
aanbod aan toestellen te gebruiken. Hoewel ze met beperkte apparaten in het achterhoofd is
ontwikkeld vormt dit geen rem wat betreft de inzetbaarheid op meer geavanceerde toestellen.
5.1
Resourcemonitor
Een eerste demo-toepassing is een eenvoudige resourcemonitor. Deze geeft onder de vorm van
staafdiagrammen het gebruik van de laatste seconden weer. In figuur 5.1 zijn enkele screenshots
te zien van de monitor in actie.
(a)
(b)
Figuur 5.1: (a) Monitor van het CPU-gebruik, (b) Monitor van het RAM-gebruik.
5.2 MediaPlayer
5.2
56
MediaPlayer
De eigenlijke demotoepassing is een mediaplayer. Wat deze player anders maakt dan bestaande
players is dat deze rekening zal houden met de eigenschappen van het platform waarop hij
gebruikt wordt.
Allereerst zal de grootte van het scherm bepaald worden en kan aan de hand hiervan de displaygrootte van het videobestand bij het starten aangepast worden. Maar ook tijdens het afspelen
van de video kan de schermgrootte dynamisch aangepast worden zonder tussnkomst van de
kijker. Deze dynamische aanpassingen worden veroorzaakt door het gebruik van de processor.
Indien het processorgebruik boven een bepaalde kantelwaarde stijgt zal de schermgrootte kleiner
gemaakt worden, en omgekeerd.
Een meer ingrijpende wijziging is het kiezen van het bronbestand op basis van het processorgebruik. Bij het overschrijden van de kantelwaarde zal dan een ander bronbestand gebruikt
worden.
Het is de moeite waard om dergelijke aanpassingen op basis van het processorgebruik te doen
want:
• Het is aangenamer om een video in lagere kwaliteit of op een kleiner scherm te bekijken
in plaats van in alle pracht en glorie maar met schokjes
• We kunnen nog steeds de video bekijken wanneer er in de achtergrond andere programma’s
rekenwerk aan het verrichten zijn, ook al is het dan tegen een lagere kwaliteit. (Om de
andere programma’s niet te veel te vertragen.)
• We kunnen het processorgebruik aanwenden om de batterij te sparen, want een zwaar
belaste processor verbruikt meer.
• Sommige toestellen zorgen ervoor dat de processorsnelheid teruggeschakeld wordt bij lagere
belasting of het niet aangesloten zijn op de netspanning. Ook dit komt de levensduur van
de batterij ten goede.
5.2.1
Gebruikte resources
Om de vermelde functionaliteit te verwezenlijken zijn 2 resources van onze API nodig.
5.2 MediaPlayer
57
Statisch: Display
Eerst en vooral is er een scherm vereist, en daarnaast is de resolutie van het scherm belangrijk.
Dit om te kunnen bepalen tegen welke ratio het beeld moet geschaald worden, opdat het het
volledige scherm zou innemen, of slechts een deel ervan.
Dynamisch: CPU
Naast het scherm speelt de processor de belangrijkste rol bij het afspelen van videobestanden.
De belasting van de processor wordt bepaald door een aantal factoren. Eerst en vooral is er de
gebruikte videocodec. Codecs die een hogere compressie aanbieden vereisen meer rekenkracht
dan codecs die nauwelijks of geen compressie gebruiken.
Een tweede factor is de resolutie en bitrate, al dan niet variabel, van het media-bestand. Als derde factor is er dan nog de herschaling van de weergave. Indien een video niet in de oorspronkelijke
verhoudingen of resolutie weergegeven wordt dient deze uitgerokken of ingekrompen te worden.
Deze bewerking vergt op zich ook weer extra rekenkracht. Doorgaans vraagt het inkrimpen van
het media-bestand veel minder resources dan het uitrekken ervan.
Figuur 5.2: De mediaplayer in actie
5.2.2
Instellingen
De door de gebruiker instelbare eigenschappen van de player zijn de volgende:
CPU threshold bronbestand De waarde van het CPU gebruik vanaf waar dient overgeschakeld te worden naar het andere bronbestand. Bij het overschrijden van een hogere naar
5.3 Java Media Framework
58
lagere waarde zal overgeschakeld worden naar het bestand met lagere kwaliteit. In het
andere geval naar een bestand met hogere kwaliteit.
CPU threshold schermgrootte De waarde van het CPU gebruik vanaf waar dient overgeschakeld te worden naar een andere schermgrootte. Bij het overschrijden van een hogere
naar lagere waarde zal overgeschakeld worden naar een kleinere schermgrootte. In het
andere geval naar een grotere schermgrootte. De schermgroottes die gebruikt worden zijn
ook door de gebruiker instelbaar, en indien gewenst wordt de player telkens gecentreerd
op het scherm bij elke wijziging.
Minimaal wijzigingsinterval voor het bronbestand De tijd die dient te verstrijken vooraleer een wijziging van het bronbestand mag plaatsvinden. Dit is nodig opdat de wijzigingen
elkaar niet te snel opvolgen en om te voorkomen dat een korte piek of daling een wijziging
zouden veroorzaken.
Minimaal wijzigingsinterval voor de schermgrootte De tijd die dient te verstrijken vooraleer een wijziging van de schermgrootte mag plaatsvinden.
Wel of niet wijzigingen doorvoeren Dit laat toe in te stellen welke wijzigingen plaats mogen hebben. Zo kunnen enkel wijzigingen van het bronbestand of van de schermgrootte
toegelaten worden.
Zoals uit bovenstaand lijstje blijkt, kunnen er 2 thresholds voor het CPU-gebruik ingesteld
worden. Deze twee waarden kunnen volledig vrij ingesteld worden en zullen de volgorde bepalen
van de kwaliteitsvermindering. Er zijn slechts twee waarden instelbaar, want indien er meer
mogelijkheden zouden zijn zal dit tot een vaak wijzigende player leiden. En dit gaat de kijkervaring eerder negatief beı̈nvloeden in plaats van positief, wat toch wel de bedoeling is.
Een handleiding van de mediaplayer is terug te vinden in appendix G.
5.3
Java Media Framework
Het afspelen van multimediabestanden zoals video is in Java niet zonder meer mogelijk. Er
bestaat echter een optioneel framework, het Java Media Framweork (JMF) wat een uitbreiding
is op het standaard J2SE platform, dat dit alles wel mogelijk maakt. Er volgt nu een lijstje met
aandachtspunten in verband met het gebruik van het JMF, met daarna een kort overzicht van
de alternatieven.
5.3 Java Media Framework
5.3.1
59
Installatie
De installatie van het JMF is helemaal geautomatiseerd en hier valt eigenlijk niets speciaal
over te zeggen. Het is echter belangrijk te weten dat de packages beschikbaar gesteld door het
framework apart in het classpath dienen opgenomen te worden. Indien men dus het JMF in
combinatie met een OSGi-platform wenst te gebruiken dient men ervoor te zorgen dat dit ook
effectief zo is bij het starten van het OSGi-framework.
5.3.2
Mogelijkheden
Het JMF maakt gebruik van platformafhankelijke codecs, beschikbaar voor het gebruikte platform. Er zijn versies beschikbaar voor Windows, Linux en Solaris. Daarnaast is er ook een
platformonafhankelijke versie helemaal in Java. Deze versie is echter enkele grootte-ordes trager
dan de platformspecifieke versies.
Het aantal ondersteunde codecs is jammer genoeg niet erg uitgebreid, dit is voor een deel te
wijten aan licentieperikelen. Maar er bestaan ook codecs die achteraf kunnen geı̈nstalleerd
worden. Zo biedt IBM een mpeg4-codec aan1 .
5.3.3
Alternatieven
Vooraleer het JMF te kiezen als basis voor deze mediaplayer werden ook een aantal andere opties
overwogen. Deze maakten allen gebruik van een bestaande player.
Een eerste mogelijkheid was om de Quicktime player van Apple te gebruiken, deze heeft een
Java-interface waardoor deze heel eenvoudig vanuit Java kan gebruikt worden of in een Javaapplicatie kan geı̈ntegreerd worden.
Verder kon ook nog Windows Media Player (of eender welke andere player) gebruikt worden.
Het nadeel van deze optie is dat deze niet rechtstreeks vanuit Java kan aangesproken worden.
Het zou dus nodig geweest zijn om zelf een Java-interface te definiren die via JNI zou toelaten
om deze player te besturen vanuit de applicatie.
De keuze is gevallen op JMF omdat op deze manier het project helemaal in Java kan ontwikkeld
worden en omdat dit een grotere vrijheid laat wat betreft ontwerp van de applicatie. Bovendien
1
http://www.alphaworks.ibm.com/tech/mpeg-4
5.4 Architectuur
60
is JMF beschikbaar voor alle platformen waarvoor J2SE beschikbaar is. Al dan niet onder de
vorm van een tragere Java-implementatie.
5.4
Architectuur
De algemene architectuur van de mediaplayer zal hier geschetst worden, met de nadruk op het
gebruik van de resource- en monitor API. De volledige broncode voorzien van commentaar is te
vinden in appendix I.
De code van de player is ondergebracht in 3 packages: dynamicmedia, dynamicmedia.player
en dynamicmedia.player.util. waarbij deze respectievelijk de grafische user interface (GUI), de
eigenlijke player en de hulpklassen voor de player en GUI bevatten. De centrale klasse in het
ontwerp is de eigenlijke player, MultiSourcePlayer.
5.4.1
MultiSourcePlayer
De playerklasse is opgevat als een black box waar een aantal instellingen van kunnen aangepast
worden en die al het werk intern afhandelt. Om de gebruikers van deze klasse op de hoogte te
stellen van eventuele wijzigingen van de player zal deze events genereren. De GUI, als gebruiker
van de klasse, zal zich dan als luisteraar bij de player registreren.
In figuur 5.3 vinden we een overzicht van de belangrijkste methoden van de player terug. Deze
omvatten een aantal getters en setters om de instellingen aan te passen en ook de methoden
getVideoScreen() en getController(). Analoog aan de methoden voorzien door de interface
Player in het JMF.
Intern maakt de player gebruik van twee UsageThresholdMonitors om het CPU-gebruik in
de gaten te houden. Wanneer deze een event genereren, zal de player na de ingestelde wachttijd
controleren of de overschrijding van de threshold blijvend is. Indien dit het geval is, wordt er
een event gegenereerd.
Wanneer beide thresholds naar boven overschreden worden, zal de player na het verloop van de
wachttijd van de monitor met de laagste threshold een eerste event genereren. Pas dan begint
de tweede wachttijd. Op deze manier kunnen de twee kwaliteitswijzigingen nooit samen plaats
hebben en gebeuren de wijzigingen altijd in de juiste volgorde. Het voorkomt bovendien dat we
5.5 OSGi-compatibel
61
MultiSourcePlayer
+getVideoScreen()
+getController()
+getPreferredScreenSize()
+setQualityControl()
+getQualityControl()
+setScreenControl()
+getScreenControl()
+setQualityThreshold()
+getQualityThreshold()
+setScreenThreshold()
+getScreenThreshold()
+setScreenTime()
+getScreenTime()
+setQualityTime()
+getQualityTime()
+addListener()
+addMediaFile()
Figuur 5.3: De implementatie-klasse van de mediaplayer met de belangrijkste methoden.
twee wijzigingen doorvoeren, waar één zou volstaan. Hetzelfde geldt uiteraard ook indien beide
thresholds naar beneden overschreden worden.
5.4.2
Grafische user interface
De grafische user interface zal een instantie van de player aanmaken en zich als luisteraar registreren. De events waarop de GUI zal reageren zijn ofwel een wijziging van het bronbestand ofwel
een wijziging van de schermgrootte. In het eerste geval zal met de methode getVisualScreen()
de display van het nieuwe bronbestand opgevraagd worden om de bestaande display te vervangen. Indien het gaat om een wijziging van grootte, zal aan de hand van de event bepaald worden
of een grotere of kleinere weergave gewenst is. Vervolgens wordt de gewenste grootte berekend
in functie van de ingestelde verhouding en de grootte van het computerscherm, waarna deze
nieuwe grootte ook effectief ingesteld wordt.
5.5
OSGi-compatibel
De player wordt verondersteld te werken binnen een OSGi-omgeving en dus dienen een aantal
maatregelen genomen te worden. Dit opdat de klassen kunnen verpakt worden in een bundel
die in eender welke OSGi-omgeving kan ingeplugd worden waarbinnen ook al de resource API
geı̈nstalleerd is.
5.5 OSGi-compatibel
5.5.1
62
Activator
Elke bundel heeft een Activator nodig, deze zal ook onmiddellijk als main klasse fungeren opdat
de player ook alleenstaand kan gebruikt worden. In deze Activator zal bij het starten eerst
informatie over de display opgevraagd worden. Indien er geen display aanwezig is zal de bundel
het start-proces onmiddellijk beëindigen en zich weer afsluiten. Hetzelfde zal gebeuren indien
de display niet grafisch is.
Indien er een geschikte display aanwezig is op het apparaat zal er een referentie naar de
MonitorService opgevraagd worden aan de OSGi-omgeving. De player maakt intern immers
gebruik van Monitors, en deze dienen geregistreerd te worden bij deze service. Indien de player
buiten een OSGi-omgeving gestart wordt zal er een MonitorService gecreëerd worden met
behulp van de MonitorServiceFactory, die speciaal voor dat geval voorzien is.
Eens ook dit verwezenlijkt is wordt de player gestart en wacht deze op interactie van de gebruiker.
5.5.2
Instellingen
De voorkeuren die de gebruiker kan instellen dienen bewaard te worden, zodat bij elke herstart van de player deze niet telkens opnieuw moeten ingegeven worden. Het OSGi-framework
schermt de bundels echter een beetje af van het onderliggende platform en het opslaan van deze
instellingen vraagt dus een beetje extra werk.
Het OSGi-framework laat ons toe met gewone bestanden te werken, net zoals we dit in een
gewone Java-applicatie zouden doen, maar i.p.v. rechtstreeks het bestand aan te maken of te
openen dient dit via de BundleContext te gebeuren. Het creëren of openen van een bestand
gaat dan als volgt:
File f = bc.getDataFile(file)
Waar bc de BundleContext is, en file een String met de bestandsnaam. Indien het bestand
niet kan geopend of gecreëerd worden zal deze methode null teruggeven. Eens deze File
verkregen is, verloopt het gebruik van het bestand net zoals in een stand-alone applicatie.
5.6 Besluit
5.6
63
Besluit
Als eindresultaat van dit hoofdstuk hebben we een mediaplayer gerealiseerd die gebruik maakt
van de resources- en monitor-API, en aldus de werking en het nut ervan demonstreert. De
player kan op meerdere apparaten gebruikt worden en zal zich naargelang het CPU-gebruik
anders gedragen.
De implementatie van deze applicatie zou zonder de opgestelde API niet mogelijk geweest zijn,
tenzij door zelf via de nodige native methoden alle informatie op te vragen. Dus hoewel het
gebruik van de API een beetje extra programmeerwerk vroeg, blijft dit toch een veel eenvoudigere
oplossing dan het alternatief en alles zelf te gaan doen. Bovendien zorgt het gebruik van de API
ervoor dat de applicatie zelf platformonafhankelijk blijft.
BESLUIT
64
Hoofdstuk 6
Besluit
Het belangrijkste doel van deze thesis was het opstellen van een duidelijke API die toelaat om
meer informatie over het gebruikte platform te verkrijgen. Zowel wat betreft statische als zeer
dynamische resources zoals het scherm, het geheugen, de processor . . . Daarnaast is er ook
een structuur voorzien die het eenvoudig maakt om de resources te gaan monitoren. Daardoor
wordt het mogelijk waarschuwingen te krijgen wanneer er bepaalde gedragingen in de resources
optreden, bijvoorbeeld het gebruik overschrijdt een vooraf ingestelde waarde.
Deze specificatie werd daarna ook succesvol geı̈mplementeerd op de TabletPC met WindowsXP
Tablet Edition als besturingssysteem. Deze implementatie voldoet aan de eisen gesteld door de
specificatie en is beschikbaar als OSGi-bundel.
Parallel met deze thesis werd ook een implementatie voor PocketPC voorzien. [20]
Dankzij deze API en bijhorende implementaties liggen de poorten naar platformonafhankelijke
adaptieve software open. Het is nu mogelijk software te schrijven die op een variëteit van
toestellen werkt en zich dynamisch aanpast aan de mogelijkheden ervan.
Het is niet meer nodig een keuze te maken om ofwel platformonafhankelijke software, ofwel
adaptieve software te ontwikkelen. Ook de ontwikkeling en het onderhoud van de software
wordt eenvoudiger daar er geen parallelle versies meer moeten onderhouden worden. Eén enkele
versie volstaat voor alle platformen.
De voordelen manifesteren zich ook op het gebruikersniveau, want niet enkel kan je altijd en
overal hetzelfde softwarepakket gebruiken, het volstaat ook om één versie aan te schaffen.
Een demonstratie van de mogelijkheden is gegeven door het ontwikkelen van een mediaplayer die
BESLUIT
65
naargelang het processorgebruik de kwaliteit van de weergave aanpast door de schermgrootte te
wijzigen of een minder belastend bronbestand te kiezen.
Toekomstig werk
Natuurlijk is er altijd ruimte voor uitbreiding en verbetering. Dit bleek al tijdens de ontwikkeling
en implementatie van de API. Af en toe dook reeds een onvoorzien probleem op door beperkingen
van het doelplatform of omwille van een kleine onvolkomenheid in de specificatie. (Zie appendix
E voor de wijzigingen die om deze reden zijn gemaakt.) Indien er nog verborgen problemen
zijn met de specificatie, is de kans groot dat deze aan het licht zullen komen bij bijkomende
implementaties voor andere platformen. Het ondersteunen van meerdere platformen is ook de
meest voor de hand liggende uitbreiding.
Eén van de meest belangrijke doelstellingen is echter ook de API gebruiken. Dit is immers de
meest adequate manier om te ontdekken of aan alle noden voldaan is. Het is immers onmogelijk
om reeds bij de ontwikkeling alle mogelijke gebruiken te voorzien.
Ook de mediaplayer kan nog verder uitgebreid en verbeterd worden. Een voor de hand liggende
stap zal erin bestaan om naast lokale bestanden ook streaming media te ondersteunen. In
dat geval kan naast het processorgebruik ook rekening gehouden worden met de beschikbare
bandbreedte. Het Java Media Framework biedt reeds ondersteuning voor streaming media,
doch zal deze uitbreiding speciale aandacht vereisen. Het wijzigen van bronstream zal immers
veel minder snel kunnen dan het wijzigen van bronbestand. Om toch nog een vloeiende weergave
te kunnen behouden zal er moeten gebruik gemaakt worden van een buffer.
EEN OVERZICHT VAN OSGI-IMPLEMENTATIES
66
Bijlage A
Een overzicht van
OSGi-implementaties
De OSGi Alliance biedt een framework aan voor het verdelen en beheren van applicaties en
services naar allerlei apparaten in een netwerk, wat niet wegneemt dat het framework ook perfect
bruikbaar is op stand-alone apparaten. De OSGi Alliance geeft echter enkel een specificatie en de
implementatie wordt overgelaten aan derden. Hier volgt een overzicht van enkele implementaties
die we getest hebben.
Allereerst moet opgemerkt worden dat er nogal wat verschillen zijn tussen de verschillende
implementaties. Uiteraard is dit geen probleem, zolang ze maar voldoen aan de opgelegde specificatie. Het is echter hier dat het soms misloopt. Niet alle implementaties houden zich voor
100 % aan de specificatie of implementeren deze reeds volledig. Een voorbeeld dat opviel, was
dat SMF verwacht dat er in de manifestheader Bundle-NativeCode aanhalingstekens staan
rond de naam van het besturingssysteem wanneer daarin spaties voorkomen. Wanneer de aanhalingstekens er wel staan, werkt de bundel dan weer niet in JES of OSCAR. KnopflerFish
ondersteunt beide versies van de header. Deze verwarring wordt waarschijnlijk veroorzaakt
doordat de OSGi-specificatie [1, sec. 4.6] hier wat afwijkt van de bestaande Manifest-conventies
voor Jar-files1 . Deze zijn op hun beurt geı̈nspireerd op RFC8222 . In de OSGi-specificatie [1,
sec. 4.6] kan de waarde van een parameter een token of een quoted string te zijn. In de bestaande Manifest-conventies wordt echter geen gebruik gemaakt van quoted strings, waar dit in
1
2
http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html#JAR%20Manifest
http://www.faqs.org/rfcs/rfc822.html
A.1 Java Embedded Server
67
RFC822 wel het geval is. Het probleem blijkt dus te ontstaan doordat Oscar en JES de naam
van het besturingssysteem als een token zien, waar SMF dit als een quoted string ziet en ze
niet beiden ondersteunen zoals het eigenlijk hoort. Enkel KnopflerFish kan overweg met beide
interpretaties.
A.1
Java Embedded Server
JES 2.0 is de implementatie van Sun. Ze schiet tekort op enkele punten. Zo is ze niet in staat om
goed om te gaan met native code. Zo werken enkel bundels die maar van één native bibliotheek
gebruik maken. Bovendien werkt het updatemechanisme niet voor bundels met native code.
Toch heeft JES ook zijn goede kanten. JES is voorzien van een zeer handige webinterface
om het framework te beheren, het remote management panel. Via deze webpagina kunnen
bundels geı̈nstalleerd en gedeı̈nstalleerd worden met enkele muisklikken. Dit is veel productiever
en overzichtelijker dan commando’s typen in een tekstinterface zoals alle implementaties die
aanbieden. Het beheren kan zelfs vanop afstand gebeuren. Je hoeft immers alleen maar naar de
administratiepagina surfen op het IP-adres van het apparaat.
A.2
OSCAR
OSCAR 0.9.4pre1 is een open-sourceproject. Het voordeel hiervan is dat het mogelijk is zelf
dingen aan te passen of toe te voegen, of in ieder geval bekijken hoe de implementatie in elkaar
zit. Het belangrijkste nadeel is dat OSCAR niet voor 100 % voldoet aan de standaard. Ook
hier is de ondersteuning voor native code niet perfect, alhoewel het meestal wel lukt. Ook het
specifiëren van meerdere beturingssystemen en/of architecturen werkt net zoals in JES niet.
Toch nog een pluspunt: ook OSCAR heeft optioneel een (heel beperkte) grafische interface in
Swing.
A.3
Knopflerfish
Knopflerfish 1.0.2 is eveneens een open-sourceproject. Dit is zeker het meest gebruiksvriendelijke pakket. Standaard start het framework op in de desktop. Dat is een grafische interface
geschreven in Swing waarin de bundels kunnen beheerd worden. Het nadeel hiervan is dat de
A.4 Service Management Framework
68
desktop niet beschikbaar is in J2ME, omdat Swing daar niet bestaat. Er is geen remote management mogelijk met de desktop. Er wordt wel een bundel aangeboden waarmee telnettoegeng
mogelijk zou moeten zijn, maar die werkt niet naar behoren. Nog een vervelende bug is dat het
deı̈nstalleren van bundels niet altijd lukt. Langs de andere kant, Knopflerfish implementeert de
OSGi-specificatie praktisch volledig.
De recentste versie van Knopflerfish is 1.3.0. Deze kwam echter te laat uit om nog uitvoerig te
gebruiken en te testen. Deze versie implementeert nu Release 3 van de OSGi-specificatie. De
gebruikersinterface is nog beter en de remote toegang via telnet is gerepareerd. Nadat we de
bug gemeld hadden i.v.m. het deı̈nstalleren van bundels werd ook dit foutje verbeterd. Remote
management is nu mogelijk met een optionele bundel.
A.4
Service Management Framework
SMF 3.5.2 is de implementatie van IBM. Zoals verwacht mag worden van een commerciële implementatie werkt alles naar behoren. Het enige wat soms niet werkt is het updaten van bundels
die een service registreren. Er worden ook heel veel bundels meegeleverd bij het framework. Zo
heeft SMF naast een console ook een mooie webinterface die vergelijkbaar is met die van JES.
Dit is de enige van deze vier implementaties die zonder problemen kan overgedragen worden op
J2ME. Het is verwonderlijk dat enkel SMF specifiek voor beperkte (mobiele) apparaten gemaakt
is, terwijl dat toch vooral de doelapparaten van OSGi zijn.
A.5
Overzicht
Aangezien de verschillende implementaties de verschillende management applicaties (uiteraard)
voorzien onder de vorm van bundels is het mogelijk om deze onderling uit te wisselen. Zo is het
bv. perfect mogelijk om de Remote Management interface van JES te installeren en gebruiken
op alle andere implementaties.
A.5 Overzicht
69
JES
OSCAR
Knopflerfish
SMF
2.0
0.9.4
1.0.2
1.3.0
3.5.2
Implementeert OSGi Release
1
2-3
2
3
3
Voldoet goed aan specificatie
✘
✘
✔
✔
✔
Console interface
✔
✔
✔
✔
✔
✔✔
✔
✔✔
✔✔
✔✔
Remote management
✔
✘
✘
✔
✔
Open-source
✘
✔
✔
✔
✘
Goed geschikt voor J2ME
✘
✘
✔
✔
✔✔
Geteste versie
Grafische interface
Tabel A.1: Overzicht van OSGi-implementaties
LEDENLIJST OSGI
Bijlage B
Ledenlijst OSGi
4DHomeNet, Inc. http://www.4dhome.net/
Alpine Electronics Europe Gmbh http://www.alpine-europe.com/
AMI-C http://www.ami-c.org/
Atinav Inc. http://www.atinav.com/
Belgacom http://www.belgacom.be/
BMW http://www.bmw.com/
Cablevision Systems http://www.cablevision.com/
Deutsche Telekom http://www.telekom3.de/
Echelon Corporation http://www.echelon.com/
Electricite de France (EDF) http://www.edf.com/
Espial Group, Inc. http://www.espial.com/
ETRI http://www.etri.re.kr/
France Telecom http://www.francetelecom.fr/
Fraunhofer Gesellschaft http://www.fraunhofer.de/
Gatespace Telematics AB http://www.gatespacetelematics.com/
IBM Corporation http://www.ibm.com/
Insignia Solutions http://www.insignia.com/
Institute for Infocomm Research http://www.i2r.org.sg/
KDDI RenD Laboratories Inc. http://www.kddlabs.co.jp/
Mitsubishi Electric Corporation http://www.mitsubishielectric.com/
70
LEDENLIJST OSGI
Motorola, Inc. http://www.motorola.com/
Nokia http://www.nokia.com/
NTT http://www.ntt.co.jp/
Object XP AG http://www.objectxp.com/
Oracle Corporation http://www.oracle.com/
Panasonic Technologies, Inc. http://www.research.panasonic.com/
Philips http://www.philips.com/
ProSyst Software AG http://www.prosyst.com/
Robert Bosch Gmbh http://www.bosch.com/
Samsung Electronics Co. http://www.samsung.com/
Sharp Corporation http://www.sharp.co.jp/
Siemens http://www.siemens.com/
Sun Microsystems http://www.sun.com/
Telcordia Technologies http://www.telcordia.com/
Telefonica I+D http://www.tid.es/
TeliaSonera http://www.teliasonera.com/
Texas Instruments, Inc. http://www.ti.com/
Toshiba Corporation http://www.toshiba.co.jp/
Een actuele lijst is steeds terug te vinden op http://www.osgi.org/about/members.asp
71
BEKNOPT OVERZICHT VAN DE API
Bijlage C
Beknopt overzicht van de API
Package resources
Klassen
resources.SystemResourceFactory
java.lang.Throwable
java.lang.Exception
resources.ResourceException
resources.ResourceNotFoundException
resources.ResourceNotSupportedException
Interfaces
resources.Resource
resources.DynamicResource
resources.CPU
resources.Memory
resources.Storage
resources.NetworkConnection
resources.Power
resources.StaticResource
resources.Display
resources.Keyboard
resources.PointingDevice
Package resources.util
Klassen
resources.util.Dimension
resources.util.Properties
72
BEKNOPT OVERZICHT VAN DE API
Package resources.util.monitor
Klassen
java.util.EventObject
resources.util.monitor.ResourceEvent
resources.util.monitor.MonitorServiceFactory
resources.util.monitor.ResourceMonitor
resources.util.monitor.DynamicResourceMonitor
resources.util.monitor.CapacityChangeMonitor
resources.util.monitor.CapacityThresholdMonitor
resources.util.monitor.UsageChangeMonitor
resources.util.monitor.UsageThresholdMonitor
resources.util.monitor.PropertyChangeMonitor
Interfaces
java.util.EventListener
resources.util.monitor.ResourceListener
resources.util.monitor.MonitorService
73
BEKNOPT OVERZICHT VAN DE IMPLEMENTATIE
Bijlage D
Beknopt overzicht van de
implementatie
Package be.ugent.resources
Klassen
be.ugent.ibcn.resources.Resource
be.ugent.ibcn.resources.DynamicResource
be.ugent.ibcn.resources.CPU
be.ugent.ibcn.resources.DiskStorage
be.ugent.ibcn.resources.NetworkConnection
be.ugent.ibcn.resources.Power
be.ugent.ibcn.resources.RAMMemory
be.ugent.ibcn.resources.ROMStorage
be.ugent.ibcn.resources.VirtualMachineMemory
be.ugent.ibcn.resources.StaticResource
be.ugent.ibcn.resources.Display
be.ugent.ibcn.resources.Keyboard
be.ugent.ibcn.resources.PointingDevice
Package be.ugent.resources.util.monitor
Klassen
be.ugent.ibcn.resources.util.monitor.MonitorServiceImpl
be.ugent.ibcn.resources.util.monitor.ServiceActivator
74
API SPECIFICATIE CHANGELOG
75
Bijlage E
API specificatie changelog
In de tijd tussen de eerste versie van de API-specificatie en de definitieve versie die in deze thesis
voorgesteld wordt, zijn enkele wijzigingen gebeurd. De ingrepen waren nooit drastisch, maar
kwamen voort uit noden of bedenkingen die pas aan het licht kwamen tijdens het implementeren
van de API of tijdens het testen ervan. Hier volgt een kort overzicht van wat er veranderd werd
en waarom. Naast de definitieve versie kunnen ook de oudere versies teruggevonden worden op
de CD-ROM.
Versie oktober 2003
• De eerste afgewerkte versie.
Deze werd gebruikt als vertrektpunt van de implementatie.
Versie maart 2004
• Een nieuw type exceptie toegevoegd in package resources: ResourceNotSupported.
Deze exceptie kan opgeworpen worden door de methoden uit SystemResourceFactory
wanneer een resource opgvraagd wordt dat niet ondersteund wordt door de implementatie.
Tijdens het implementeren van de API voor de PocketPC bleek dat de beperkte API van
Windows CE/PocketPC niet alle functionaliteit toelaat die nodig is voor een volledige
implementatie. Zo is het bijvoorbeeld onmogelijk om gegevens over de CPU op te vragen.
Om dit op te vangen werd een extra exceptie toegevoegd, om het onderscheid te kunnen
maken tussen een onbestaande resource en een ongeı̈mplementeerde resource.
API SPECIFICATIE CHANGELOG
76
Versie april 2004
• Methoden verwijderd uit SystemResourceFactory.
Deze klasse bevatte voor elke getXXX()-methode een methode met dezelfde signatuur op
een extra argument na. Dit argument was van het type Class. Deze klasse werd dan
door de methode geı̈nstantieerd. De bedoeling was het dynamisch uitbreidbaar maken van
de API. Deze methoden werden uiteindelijk niet nuttig bevonden. Ze moedigen aan om
rechtstreeks met implementatieklassen te werken in plaats van via een interface. Dit komt
de uniformiteit niet ten goede. Als men dan toch een eigen implementatie wil gebruiken
voor een resource, kan men bovendien evengoed zelf een instantie maken met new in plaats
van dat door een methode te laten doen.
• Hernoemen van methode getNetworkConnections() naar getNetworkConnectionNames()
om consistent te zijn met getStorageNames().
• Definitieve versie.
HOWTO: GEBRUIK VAN DE API
77
Bijlage F
Howto: gebruik van de API
Deze bijlage heeft tot doel een kleine inleiding te geven in het gebruik van de API en de integratie
met het OSGi-framework. In hoofdstuk 3 werd reeds door middel van voorbeeldcode het gebruik
geschetst. Hier worden enkele volledig uitgewerkte voorbeeldjes beschreven om zo het geheel te
verduidelijken. Alle code uit deze appendix is integraal terug te vinden op de bijgevoegde cdrom.
F.1
Opmerkingen
Alle voorbeeldjes zijn OSGi-bundles. Zoals beschreven in hoofdstuk 2 is daarom het gebruik
van een BundleActivator noodzakelijk en dienen de gecompileerde klassen correct verpakt te
worden in een JAR-file. Een BundleActivator vereist enkel de implementatie van een start- en
stop-methode. Het concrete gebruik zal onmiddellijk duidelijk worden in het eerste voorbeeldje.
Vooraleer deze bundels kunnen gebruikt worden, dienen in de OSGi-omgeving reeds de Resourcesen Monitor-bundle geı̈nstalleerd en gestart te zijn. Deze zijn eveneens terug te vinden op de
cd-rom.
F.2
Gebruik van resources en OSGi
Een eerste mogelijkheid die de API ons biedt is het rechtstreeks bevragen van resources. We
zullen informatie over het scherm opvragen en dit uitschrijven bij het starten van de bundel.
Aangezien dit alles is wat we willen doen volstaat het om enkel een BundleActivator te schrijven. Het is de gewoonte om de activator-klasse van een bundel gewoon Activator te noemen.
F.2 Gebruik van resources en OSGi
78
Dit maakt het ook voor andere programmeurs makkelijk om deze klasse terug te vinden.
F.2.1
Broncode
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import resources.Display;
import resources.SystemResourceFactory;
/**
* Heel eenvoudige bundle die Informatie over het scherm uitprint.
*/
public class Activator implements BundleActivator {
De eerste twee import-statements zijn nodig omdat we een bundel zullen programmeren, de
volgende statements zijn nodig om gebruik te kunnen maken van de API-implementatie. We
willen immers de resource Display opvragen en dit gebeurt via de SystemResourceFactory.
/**
* Start-methode van de bundel.
*/
public void start(BundleContext ctxt) throws Exception {
Display display = SystemResourceFactory.getDisplay();
System.out.println("Display :");
System.out.println("Grootte : "+display.getSize());
System.out.println("Kleurdiepte : "+display.getColorDepth());
System.out.println("Grafisch : "+display.isGraphical());
}
Bovenstaande stukje code bevat de start-methode van onze bundel, dit wil zeggen dat dit
de code is die uitgevoerd wordt bij het starten van de bundel. Allereerst vragen we aan de
SystemResourceFactory een instantie van de Display. Vervolgens schrijven we de grootte en
kleurdiepte uit en ook nog of het om een grafische display gaat of niet.
Het opvragen van de display genereert mogelijks een exception indien de resource Display niet
ondersteund is in de gebruikte implementatie of indien er geen display aanwezig is op het toestel.
Merk ook op dat de start-methode mogelijks altijd een exception opgooit, dus het is eigenlijk
F.2 Gebruik van resources en OSGi
79
niet nodig om deze exceptions ook daadwerkelijk op te vangen. Door dit niet te doen wordt aan
de starter van de bundel onmiddellijk duidelijk gemaakt dat er iets is misgelopen. Dit is zeker
belangrijk indien deze starter zelf ook software of een bundle is. Indien het de bedoeling is dat
deze bundel enkel door mensen gestopt of gestart wordt, dan is het vaak wel de moeite om deze
exceptions op te vangen en ’te vertalen’ naar een, voor mensen, meer begrijpbare boodschap.
/**
* Stop-methode van de bundel
*/
public void stop(BundleContext ctxt) throws Exception {}
}
De stop-methode van een bundel wordt uitgevoerd wanneer deze gestopt wordt, voor deze bundel
is het niet nodig deze in te vullen.
F.2.2
Compileren
In de bovenstaande broncode hebben we gebruik gemaakt van OSGi-specifieke klassen en van
de Resource-API klassen. Deze dienen bij het compileren in het classpath aanwezig te zijn.
Rekening houdend met de directory-structuur op de cd-rom kan bovenstaande code gecompileerd
worden met het volgende commando1 :
javac -classpath ../jars/Resources.jar;../jars/osgi.jar *.java
F.2.3
Inpakken in een JAR-file
OSGi-bundles zijn eigenlijk niets meer dan gewone JAR-files met enkele extra headers in de
Manifest. De Manifest voor deze bundel ziet er als volgt uit:
Import-Package: resources, resources.util
Bundle-Name: DisplayInfo
Bundle-Activator: Activator
Bundle-Description: Illustreert het gebruik van een Resource.
1
Op Windows-systemen is de delimiter tussen de verschillende paden een ; op Unix-systemen is dit een :
F.3 Gebruik van een default Monitor
80
De Import-Package-header geeft aan welke externe packages er gebruikt worden binnen de
bundel en de Bundle-Activator-header duidt aan welke klasse de BundleActivator is. Het
inpakken in de JAR-file kan dan als volgt:
jar -cvfm DisplayInfo.jar manifest.mf *.class
Waarbij DisplayInfo.jar de naam van de bundel is en manifest.mf de Manifest-file zoals hoger
beschreven.
F.3
Gebruik van een default Monitor
Het volgende voorbeeldje beschrijft hoe een UsageThresholdMonitor gebruikt wordt samen
met de MonitorService zoals deze aangeboden wordt binnen het OSGi-framework.
F.3.1
Code
//Import-statements zijn weggelaten.
/**
* Gebruik van een monitor.
*/
public class Activator implements BundleActivator, ResourceListener {
MonitorService ms;
UsageThresholdMonitor utm;
Opnieuw noemen we onze klasse Activator. Deze klasse zal ook onmiddellijk de listener zijn die
naar de MonitorEvents luistert en daarom implementeert ze ook de interface ResourceListener.
We voorzien de MonitorService en usageThresholdMonitor.
/**
* Start-methode van de bundel.
*/
public void start(BundleContext ctxt) throws Exception {
ServiceReference[] ref = null;
/*
* De monitorService opvragen.
F.3 Gebruik van een default Monitor
81
*/
try {
ref = ctxt.getServiceReferences(
"resources.util.monitor.MonitorService",
"(description=MonitorService)");
} catch (InvalidSyntaxException e) {
System.err.println("syntaxerror : " + e);
}
if (ref != null) {
ms = (MonitorService) ctxt.getService(ref[0]);
} else {
throw new BundleException("Monitor service not found.");
}
In het eerste deel van de start-methode vragen we via de BundleContext de MonitorService
aan de OSGi-omgeving, indien deze niet gevonden wordt, wordt een BundleException opgeworpen. We hebben de MonitorService immers nodig om onze monitor bij te registreren.
/*
* De RAM-resource opvragen.
*/
Memory ram = SystemResourceFactory.getRAM();
utm = new UsageThresholdMonitor(ram,50);
utm.addListener(this);
ms.addMonitor(utm);
}
In het tweede deel van de start-methode wordt de resource RAM opgevraagd en construeren
we hiermee een UsageThresholdMonitor. We geven als tweede argument de waarde 50 mee
aan de constructor, wat wil zeggen dat wanneer het gebruik van 50 % overschreden wordt, ofwel
naar boven ofwel naar onder, er een event zal gegenereerd worden. Daarna wordt bij de monitor
een luisteraar geregistreerd en wordt de monitor aan de MonitorService toegevoegd. Vanaf
dit moment kunnen er events gegenereerd worden.
/**
* Stop-methode van de bundel.
*/
F.3 Gebruik van een default Monitor
82
public void stop(BundleContext ctxt) throws Exception {
ms.removeMonitor(utm);
utm = null;
ms = null;
}
Wanneer de bundle gestopt wordt dienen we de monitor te verwijderen van MonitorService.
/**
* Listener-methode
*/
public void eventOccurred(ResourceEvent e) {
System.out.println("Usage :"+e.getData());
}
}
Wanneer er een event plaats heeft zullen we de waarde die meegegeven wordt uitschrijven.
F.3.2
Compileren
Het compileren verloopt net zoals bij het vorige voorbeeld, enkel wordt hier ook gebruik gemaakt
van de monitors, en dienen deze dus ook opgenomen te worden in het classpath:
javac -classpath ../jars/Resources.jar;../jars/MonitorService.jar;\\
../jars/osgi.jar *.java
F.3.3
Inpakken in een JAR-file
Ook het inpakken in de JAR-file verloop analoog aan het vorige voorbeeld. Hier dient ook nog
het monitor-package toegevoegd te worden aan de Import-Package-header. De Manifest ziet
er als volgt uit:
Import-Package: resources, resources.util, resources.util.monitor
Bundle-Name: MonitorUser
Bundle-Activator: Activator
Bundle-Description: Illustreert het gebruik van een Monitor.
F.4 Een BatterijMonitor
F.4
83
Een BatterijMonitor
Als laatste onderdeel zullen we een eigen monitor schrijven die een event genereert wanneer het
toestel overschakelt van batterij naar netspanning en omgekeerd.
F.4.1
Code
//import-statements zijn weggelaten.
/**
* Batterijmonitor die een event zal genereren wanneer er wordt
overgeschakeld
* tussen batterij en netspanning.
*/
public class PowerMonitor extends ResourceMonitor {
boolean prevState;
/**
* Constructor
*/
public PowerMonitor(Power power) {
super(power);
prevState = power.isBatteryPowered();
}
We schrijven een eigen monitor door over te erven van de bestaande abstracte klasse ResourceMonitor.
Een instantie van de klasse kan enkel geconstrueerd worden met een Power-resource, deze monitor zal immers enkel hiervoor bruikbaar zijn.
Aangezien we de overgang willen ontdekken tussen batterij en netspanning of omgekeerd is het
belangrijk te weten wat de krachtbron is op moment van constructie.
/**
* Monitor-methode
*/
public void monitor() {
boolean curState = getPower().isBatteryPowered();
F.4 Een BatterijMonitor
84
/*
* indien de huidige status en de vorige status verschillend zijn
* wordt er een event gegenereerd met de juiste boodschap
*/
if(curState != prevState) {
String msg = curState ? "batterij" : "netspanning";
prevState = curState;
fireEvent(msg);
}
}
De monitor-methode zal door het toevoegen van de monitor aan de MonitorService elk interval
aangeroepen worden. In deze methode vragen we opnieuw op wat de huidige krachtbron is en
indien dit niet meer dezelfde is als toen we dit de vorige keer hebben opgevraagd, wordt er een
event gegenereerd. Hiertoe kunnen we gebruik maken van de fireEvent-methoden al voorzien
door de abstracte ResourceMonitor-klasse. Ook alle benodigdheden om luisteraars bij onze
monitor te registreren zijn reeds voorzien.
/**
* De batterij opvragen
* @return Power
*/
protected Power getPower() {
return (Power)getResource();
}
}
Voor het gemak is ook een protected methode getPower() toegevoegd om de Power-resource
op te vragen.
Op de cd-rom is eveneens een activator die gebruik maakt van deze monitor toegevoegd.
HANDLEIDING MEDIAPLAYER
85
Bijlage G
Handleiding MediaPlayer
Eerst volgt een beschrijving van het formaat van het input-bestand, en vervolgens zullen de
instelbare opties overlopen worden.
G.1
Input
De player neemt twee bestanden als input en deze dienen in een eenvoudig tekstbestandje gespecificeerd te worden. Dit bestand ziet er bv. als volgt uit:
Vakantiefilm
file:///C:\vakantie\film\strand_high.mpeg
file:///C:\vakantie\film\strand_low.mpeg
Op de eerste lijn wordt de titel geplaatst, en vervolgens komen de twee volledig gekwalificeerde
paden naar de bestanden. Het bestand in de beste kwaliteit dient eerst te komen.
G.2
Startscherm
Figuur G.1 toont het scherm dat te zien is, net na het starten van de player.
De functionaliteit van de knoppen is de volgende:
1. een bronbestand openen;
2. het preferences-venster openen;
G.3 Preferences
86
Figuur G.1: Startscherm van de MediaPlayer
3. deze handleiding tonen;
4. een informatie-venstertje tonen;
5. de player afsluiten;
G.3
Preferences
Het venstertje met de instellingen bestaat uit 3 tabbladen:
G.3.1
Algemeen
Figuur G.2: Instellen welke acties mogen ondernomen worden.
Op het eerste tabblad (zie figuur G.2) kan ingesteld worden welke wijzigingen mogen plaatsgrijpen. Een wijziging van het bronbestand, van de schermgrootte, beiden of geen van beiden. De
G.3 Preferences
87
volgende twee tabbladen laten toe deze keuzes in te stellen.
G.3.2
Bestandskeuze
Figuur G.3: Instellingen voor de bestandswissel.
Op het tabblad voor de bestandskeuze (zie figuur G.3) kan ingesteld worden vanaf welke threshold er moet geschakeld worden tussen de verschillende bestanden. Verder is het ook mogelijk
in te stellen hoe lang er minstens tussen twee wijzigingen dient gewacht te worden.
G.3.3
Schermgrootte
Figuur G.4: Instellingen voor de schermwissel.
Op het tabblad voor de keuze van de schermgrootte (zie figuur G.4) kan net zoals bij de keuze
van het bestand een threshold en minimuminterval ingesteld worden. Daarnaast kan ook de
gewenste schermgrootte gekozen worden in functie van de grootte van de fysieke display. Deze
waarden zullen gebruikt worden bij het wijzigen van de schermgrootte. Tenslotte kan ook
aangegeven worden dat bij het wijzigen van de schermgrootte de mediaplayer dient gecentreerd
G.3 Preferences
88
te worden. Indien deze optie niet aangevinkt wordt, zal de linkerbovenhoek gebruikt worden als
referentiepunt.
TOOLS
89
Bijlage H
Tools
Eclipse Een IDE, uitermate geschikt voor Java ontwikkeling.
http://www.eclipse.org/
Ant Een build-tool om bv het compileren, builden van bundels en genereren van javadoc te
automatiseren.
http://ant.apache.org/
Microsoft Visio Ontwikkeltool om UML en andere diagrammen mee te maken.
http://www.microsoft.com/office/visio/
OpenOffice.org Office suite, gebruikt voor het maken van niet UML figuren.
http://www.openoffice.org/
MinGW Een vrije C/C++ compiler voor Windows.
http://www.mingw.org/
Microsoft Visual Studio Een IDE, zeer geschikt voor ontwikkeling in Windows.
http://msdn.microsoft.com/vstudio/
CVS Een Concurrent Versions System.
http://www.cvshome.org/
LATEX Het typesetting systeem waarmee deze tekst gemaakt is.
http://www.ctan.org/
CD-ROM
90
Bijlage I
cd-rom
• Het boek in pdf-formaat
• De presentatie zoals deze gegeven werd op de thesisverdediging op 25 mei 2004
• Software
– De drie belangrijke releases van de API
– De implementatie van de API
– De demotoepassing: een MediaPlayer en bijhorende testfilmpjes
– Een eenvoudige ResourceMonitor
– Een hulpprogramma dat toelaat om de load op de cpu kunstmatig te verhogen of te
verlagen
– Voorbeeldcode uit hoofdstuk 2 en bijlage F
• Een volledig geconfigureerde OSGi-omgeving met alle bundles voorgenstalleerd (gebaseerd
op Knopflerfish)
BIBLIOGRAFIE
91
Bibliografie
[1] OSGi. Osgi service platform release 3. Technical report, The Open Services Gateway
Initiative, March 2003. http://www.osgi.org (24 Mei 2004).
[2] Jar manifest specificaties.
http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html#JAR%20Manifest (24 Mei 2004).
[3] Java embedded server. http://java.sun.com/jes/ (24 Mei 2004).
[4] Prosyst mbedded. http://www.prosyst.com (24 Mei 2004).
[5] avelink embedded gateway. http://www.atinav.com/osgi/ (24 Mei 2004).
[6] Open source cluster application resources (oscar). http://oscar.sf.net (24 Mei 2004).
[7] Knopflerfish osgi. http://www.knopflerfish.org.
[8] Gatespace telematics ab. http://www.gatespacetelematics.com/ (24 Mei 2004).
[9] Ibm service management framework.
http://www-306.ibm.com/software/wireless/smf/index.html (24 Mei 2004).
[10] Wireless highlights and news. http://wireless.java.sun.com (24 Mei 2004.
[11] Connected limited device configuration. http://java.sun.com/products/cldc (24 Mei 2004).
[12] Connected device configuration. http://java.sun.com/products/cdc/ (24 Mei 2004).
[13] Tim Lindholm and Frank Yellin. The Java Virtual Machine Specification. Addison-Wesley,
second edition, 1999.
[14] Bill Joy, Guy Steele, James Gosling, and Gilad Bracha. Java Language specification.
Addison-Wesley, second edition, 2000. http://java.sun.com/docs/books/jls/ (24 Mei 2004).
BIBLIOGRAFIE
92
[15] Sheng Liang. The Java Native Interface, Programmer’s Guide and Specification. AddisonWesley, 1999. http://java.sun.com/docs/books/jni/ (24 Mei 2004).
[16] Developer information for the ipaq handhelds. http://h71018.www7.hp.com/ (24 Mei 2004).
[17] Microsoft windows mobile. http://www.microsoft.com/windowsmobile/ (24 Mei 2004).
[18] Symbian os - the mobile operating system. http://www.symbian.com (24 Mei 2004).
[19] Java community process. http://www.jcp.org (24 Mei 2004).
[20] Koen Van Boxstael. Resource monitoring api in java voor adaptieve software. Master’s
thesis, Universiteit Gent, 2003-2004.
[21] Kim Topley. J2ME™ in a nutshell, A desktop quick reference. O’Reilly, first edition, March
2002.
[22] Michael Juntao Yuan. Enterprise J2ME, Developing mobile Java applications. Prentice
Hall, 2004.
[23] Mikkio Kontio. Mobile Java™ with J2ME™. IT Press, 2002.
[24] The independent source for enterprise java. http://www.onjava.com (24 Mei 2004).
Download