Sie sind auf Seite 1von 336

Datenbankentwicklung mit db4o

Einfhrung in eine objektorientierte Datenbank

von

Ina Brenner

Bibliograsche Information der Deutschen Bibliothek


Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliograe; detaillierte Daten sind im Internet ber

http://dnb.ddb.de abrufbar.

Hinweis:
Alle Beispiele und Listings wurden von der Autorin sorgfltig berprft, trotzdem kann es zu
Fehlern kommen. Die Autorin kann deshalb fr etwaige Schden keine Haftung bernehmen,
die im Zusammenhang mit der Verwendung des vorliegenden Buches und aufgrund fehlerhafter
Hinweise entstehen. Die Autorin ist allerdings fr alle Hinweise auf Fehler dankbar.
c Ina

Brenner

Das vorliegende Buch ist urheberrechtlich geschtzt. Alle Rechte sind der Autorin vorbehalten.
Alle Software- und Firmenangaben, die in diesem Buch erwhnt wurden, knnen auch ohne
Kennzeichnung eingetragene Warenzeichen sein und unterliegen somit den hierfr vorgesehenen
gesetzlichen Bestimmungen des Markenschutzes.

Satz: Ina Brenner


Herstellung und Verlag: Books on Demand GmbH, Norderstedt
ISBN-13 9783837001716

Inhaltsverzeichnis

Vorwort

Danksagung

vii

1 Einleitung

1.1

Fr wen ist dieses Buch? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2

Wie geht dieses Buch vor? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3

ber NetBeans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3.1

Installation von NetBeans . . . . . . . . . . . . . . . . . . . . . . . . . . .

ber db4o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4.1

Wo ndet db4o Verwendung? . . . . . . . . . . . . . . . . . . . . . . . . .

1.4.2

Performance

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4.3

Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4

2 Einstieg in unser Projekt

2.1

Das erste J2EE-Projekt in NetBeans . . . . . . . . . . . . . . . . . . . . . . . . .

2.2

Installation von db4o:Einbinden einer Bibliothek

. . . . . . . . . . . . . . . . . .

3 Erste Datenbankabfragen in db4o

11

3.1

Erste berlegungen zu einem Datenbankentwurf: Unser erstes Objekt

. . . . . .

11

3.2

Wichtige Klassen und Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

3.2.1

Das Package com.db4o . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

3.2.2

Das Interface ExtObjectContainer

. . . . . . . . . . . . . . . . . . . . . .

15

Datenbankabfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

3.3.1

Speichern von Objekten . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

3.3.2

Auslesen von Objekten mit Query-by-Example

. . . . . . . . . . . . . . .

17

3.3.3

Lschen von Objekten . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

3.3.4

ndern von Objekten

22

3.3.5

Praktische Anwendungsbeispiele

3.3

3.4

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .

23

Zusammenfassende erste berlegungen . . . . . . . . . . . . . . . . . . . . . . . .

27

4 Ideen zu einem objektorientierten Datenbankentwurf

29

4.1

berlegungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

4.2

Theoretische Grundlagen

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30

4.2.1

Datenredundanz und Normalisierung . . . . . . . . . . . . . . . . . . . . .

31

4.2.2

Das Entity-Relationship-Modell . . . . . . . . . . . . . . . . . . . . . . . .

31

4.2.3

Referentielle Integritt . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

Theoretische Datenbankgrundlagen und db4o . . . . . . . . . . . . . . . . . . . .

32

4.3

iii

Inhaltsverzeichnis

5 Beziehungen in einem objektorientierten Datenbankentwurf


5.1

Die 1:1-Beziehung: die has-a-Beziehung


5.1.1

5.2

5.3

5.4

33

. . . . . . . . . . . . . . . . . . . . . . .

Speichern, Auslesen und Lschen von Objekten der Klasse TextEinfach

34

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

47

5.2.1

Super- und Subklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

47

5.2.2

Interfaces und Abstrakte Klassen

. . . . . . . . . . . . . . . . . . . . . .

55

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

Vererbungsbeziehungen

1:n-Beziehung
5.3.1

db4o Collections und die ArrayList

. . . . . . . . . . . . . . . . . . . . .

5.3.2

Speichern, Auslesen, ndern und Lschen von Formatierungsobjekten

. .

58

5.3.3

Text zu den Formatierungen hinzufgen . . . . . . . . . . . . . . . . . . .

67

5.3.4

Textobjekte aus der ArrayList des Formatierungsobjektes wieder entfernen

71

5.3.5

Texte auch aus der Datenbank entfernen . . . . . . . . . . . . . . . . . . .

73

5.3.6

Ergnzende Bemerkungen zum Lschvorgang von Objekten der Klasse For-

6.2

6.3

matierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

76

Texte ndern

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

79

5.3.8

Die Klasse Website . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

m:n-Beziehung

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

87

Native Queries

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

6.1.1

Speichern und Auslesen von Objekten der Klasse WebSite . . . . . . . . .

87

6.1.2

Bedingungen formulieren

6.1.3

Komplexe Abfragen

6.1.4

Sortieren

. . . . . . . . . . . . . . . . . . . . . . . . . . .

94

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

103

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

106

S.O.D.A. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

111

6.2.1

Bedingungen formulieren

. . . . . . . . . . . . . . . . . . . . . . . . . . .

112

6.2.2

Sortieren

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

121

6.2.3

Direkter Zugri auf Elemente einer ArrayList . . . . . . . . . . . . . . . .

123

Query-by-Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

124

6.3.1

124

Zugri auf Elemente einer ArrayList . . . . . . . . . . . . . . . . . . . . .

7 Aktivierungstiefe, Update-Tiefe und Tiefe Objektgraphen

127

7.1

Aktivierungstiefe und Tiefe Objektgraphen

. . . . . . . . . . . . . . . . . . . . .

127

7.2

Aktivierungstiefe und die LinkedList . . . . . . . . . . . . . . . . . . . . . . . . .

130

7.3

Update-Tiefe

130

7.4

Transparente Aktivierung

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

8 Exkurs: Threads und Multithreading


8.1

8.2

131

133

Erstellung eines Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

133

8.1.1

Mithilfe des Runnable Interfaces

. . . . . . . . . . . . . . . . . . . . . . .

133

8.1.2

Mithilfe der Klasse Thread

. . . . . . . . . . . . . . . . . . . . . . . . . .

134

Synchronisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

135

8.2.1

135

Synchronisierte Blcke . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9 Client-Server-Modus

iv

58

5.3.7

6 Abfragekonzepte
6.1

33

139

9.1

Netzwerkmodus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

139

9.2

Embedded-Modus

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

144

9.3

Out-of-Band-Signalling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

145

Inhaltsverzeichnis

10 Transaktionen

151

10.1 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.1.1 Transaktionen und die Methode refresh()

151

. . . . . . . . . . . . . . . . . .

158

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

158

10.2.1 Isolationsstufen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

159

10.3 Semaphores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

160

10.2 ACID

10.3.1 Locken von Bereichen

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

160

10.3.2 Locken von Objekten

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

162

10.3.3 Lockingprozesse in Projekten

. . . . . . . . . . . . . . . . . . . . . . . . .

11 Einstieg in J2EE

164

167

11.1 Der Model-View-Controller: Klassen, Servlets und JSPs


11.2 Zusammenspiel zwischen Servlet und JSP

. . . . . . . . . . . . . .

167

. . . . . . . . . . . . . . . . . . . . . .

168

11.2.1 Versenden von Daten mit POST und GET

. . . . . . . . . . . . . . . . .

174

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

174

11.3.1 Allgemeines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

174

11.3.2 Methoden des Interface HttpServletRequest . . . . . . . . . . . . . . . . .

176

11.3.3 Die Methode sendRedirect() des Interface HttpServletResponse . . . . . .

176

11.3.4 Sessions und die zugehrigen Methoden

. . . . . . . . . . . . . . . . . . .

177

11.3.5 Attribute, Parameter und Geltungsbereiche . . . . . . . . . . . . . . . . .

178

11.3.6 Ein praktisches Beispiel

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

178

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

182

11.4.1 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

182

11.4.2 Syntaxelemente in einem JSP . . . . . . . . . . . . . . . . . . . . . . . . .

191

11.3 Servlets

11.4 JSP

11.5 Filter

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11.6 Deployment Descriptor: web.xml

206

. . . . . . . . . . . . . . . . . . . . . . . . . . .

211

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

214

11.7.1 HttpSessionAttributeListener . . . . . . . . . . . . . . . . . . . . . . . . .

214

11.7.2 ServletContextListener . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

216

11.7.3 HttpSessionListener

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

216

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

217

11.7 Listener

11.7.4 Weitere Listener

12 Embedded-Modus in einem Web-Projekt


12.1 Die Methode refresh()

219

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

226

12.2 Update-Tiefe im Embedded Modus . . . . . . . . . . . . . . . . . . . . . . . . . .

227

13 Unser Content-Management-System

235

13.1 Allgemeines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

235

13.2 Eingabe, Auslesen, Lschen und ndern der Formatierungen

. . . . . . . . . . .

235

13.3 Eingabe von Objekten der Klasse WebSite . . . . . . . . . . . . . . . . . . . . . .

248

13.3.1 Eingabe des Hyperlinks, der Reihenfolge und der Ebene

. . . . . . . . . .

261

13.3.2 Eingabe von Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

264

13.3.3 Eingabe von Bildern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

266

13.3.4 Eingabe von PDFs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

269

13.3.5 Das Eingabe-Servlet

271

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13.4 Ausgabe von Objekten der Klasse WebSite

. . . . . . . . . . . . . . . . . . . . .

280

13.5 Lschen von Objekten der Klasse WebSite . . . . . . . . . . . . . . . . . . . . . .

288

13.6 ndern von Objekten der Klasse WebSite

295

. . . . . . . . . . . . . . . . . . . . . .

13.6.1 ndern des Hyperlinks, der Reihenfolge und der Ebene

. . . . . . . . . .

297

Inhaltsverzeichnis

13.6.2 ndern des Textes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

299

13.6.3 ndern der Bilder

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

302

13.6.4 ndern der PDFs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

304

13.6.5 Das ndern-Servlet

307

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14 Anhang
14.1 Literaturverzeichnis

vi

319
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

319

14.2 Weitere Informationsquellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

319

Vorwort
Echte Innovationen kommen erst einmal auf leisen Fen daher. So auch db4o, die Datenbank,
die das Leben von Java und .NET Programmierern so viel einfacher macht. Die macht keine
groartige Werbung oder ist auf groen und teuren Messestnden vertreten, sondern vor allem
im Herzen der Entwickler, die die Datenbankmaschine kostenlos unter der GPL OpensourceLizenz heruntergeladen haben, ausprobiert haben, und nicht mehr zurckblicken wollen.
Denn in moderner, objektorientierter Softwareprogrammierung wird, je nach Anwendung, 10-50%
der Zeit und des Geldes darauf verwendet, Objekte in inkompatible, relationale Datenbanktabellen hineinzupressen, oder - noch schlimmer - hausgemachte Persistenzlsungen basierend auf
achen, proprietren Dateien zu hacken. Das ist nicht nur verwunderlich, da Daten abspeichern ja
eigentlich eine ganz grundstzliche und einfache Anforderung ist, sondern vor allem unglaublich
inezient.
Das Problem ist dass sich irgendwann einmal in unseren Kpfen festgesetzt hat, dass eine Datenbank nun einfach mal relational strukturiert sein muss. Das ist genauso wahr wie die berzeugung, dass die Erde ach ist. Man glaubt nicht an die Kugel - bis man sie dann mal gesehen
hat.
R , der Hersteller der fhrenden relationalen Datenbank gibt zu: Das Herstellen
Selbst Oracle

von Java-Anwendungen mit relationalen Datenbanken ist wahrscheinlich die am meisten unterschtzte Herausforderung in der heutigen Unternehmenssoftware-Entwicklung. Mehr und mehr
Projekte sind versptet, haben fehlende Funktionen oder sind schwer zu warten wegen dieser
Fehleinschtzung. Das Problem liegt in der Anwendung grundstzlich verschiedener Technologien. Die Objektwelt und die relationale Welt passen nicht zusammen. 1

Computer-Vordenkerin Esther Dyson hat das noch pointierter ausgedrckt: Tabellen zu verwenden um Objekte abzuspeichern - das ist wie wenn Sie Ihr Auto jeden Abend auseinanderbauen
um es in die Garage zu bringen. Sie knnen es am nchsten morgen wieder zusammenschrauben,
aber irgendwann fragt man sich dann doch, ob das die ezienteste Art ist, ein Auto zu parken. 
Durch db4o ist mit diesem Unsinn Schlu: Objekte in der Applikation sind Objekte in der Datenbank. Ein einheitliches Schema ersetzt den freundlich dual genannten Ansatz, der schlicht eine
massive Redundanz und riesige Synchronisationskosten bedeutet. Obwohl es sicher sinnvolle Anwendungen fr relationale Datenbanken und den dualen Ansatz gibt, gibt es doch viele Gebiete,
wo sich die massiven Ezienzsteigerungen durch db4o direkt in Wettbewerbsfhigkeit, bessere
Produkte, weniger Kosten- und Terminverzgerung sowie besser wartbare und wiederverwendbarere Softwarekomponenten umsetzen lassen.
Ina Brenner hat sich in die Fangemeinde von db4o eingereiht, die nach 1 Millionen Downloads
schon weit ber 20,000 registrierte Entwickler in ihrer Community (http:\\developer.db4o.com)
zhlt, und jetzt ein neues, wunderbares Buch verfasst, das die ganz praktische Anwendung von
db4o, Schritt fr Schritt, zeigt und so hoentlich wieder viele neue Freunde fuer diese revolutionre Technologie rekrutiert.

1 Building

Java applications that use relational databases is perhaps the single most underestimated challenge
in enterprise development today. More projects are delayed, under-featured and dicult to maintain because
of this underestimation. The problem lies with the use of fundamentally dierent technologies. The object
world and the relational world do not match up. , Oracle Corporation, An Oracle Whitepaper, September
2005,http:\\www.oracle.com\technology \products\ias\toplink\technical \TopLink_WP.pdf

vii

Vorwort

Dass das Buch in deutsch verfasst ist, ist besonders bemerkenswert, da db4o in Deutschland
konzipiert wurde und dort besonders populr ist, auch wenn die dazugehrige Firma, db4objects,
Inc., im kalifornischen Silicon Valley zuhause ist und mit Kunden, Anwendern und Mitarbeitern
rund um den Globus zusammenarbeitet.
Wir wnschen dem Leser viel Spa beim Entdecken, warnen aber schon vorab, dass db4o schtig
macht: Sie werden nie mehr zurck gehen wollen in die Zeit, wo Sie sich den Kopf ber das
Speichern von Objekten zerbrechen mssen, sondern sich einfach um Ihre tatschliche Applikationsdomne kmmern knnen!
Ihr
Christof Wittig CEO db4objects, Inc.

viii

Danksagung
Es ist mir ein Vergngen, alle Personen zu wrdigen, die in den verschiedenen Phasen des Schreibens mir zur Seite gestanden sind und mit Ihrem Engagement sehr zum Erfolg dieses Buches
beigetragen haben:
Meinen Dank gilt Herrn Burbiel, dessen Vorschlge mir von groem fachlichen Nutzen waren.
Sein Fachwissen hat zur Qualitt des vorliegenden Buches beigetragen.
Auerdem bin Herrn Prof. Dr. Stefan Edlich und Majk Jablonski zu Dank verpichtet, die mir
mit Verbesserungsvorschlgen zur Seite gestanden sind.
Besonders erwhnen mchte ich die Untersttzung durch db4o, insbesondere Herrn Christof
Wittig, der mit seinem Engagement reges Interesse an meinem Buch gezeigt hat und mich in
allen Phasen untersttzt hat.
Und last but not least, bedanke ich mich bei dem englischsprachigen db4o-Forum.

ix

1 Einleitung
Haben Sie nicht schon immer Probleme mit dem Zusammenspiel Ihrer relationalen Datenbank
und Java? War es nicht immer schwierig fr Sie, Objekte in Tabellen zu quetschen? Wollten Sie
nicht schon immer Objekte direkt in der Datenbank abspeichern? Dann gibt es jetzt die optimale
Lsung fr Sie, nmlich db4o. Sie ist die Lsung all Ihrer Probleme! Sie brauchen nur noch Java,
Microsoft .NET oder Mono und schon knnen Sie direkt in db4o Objekte ein- und wieder auslesen.
Bisher stellt Hibernate das Zwischenstck zwischen relationaler und objektorientierter Welt dar,
das in Zukunft nicht mehr bentigt wird, da es mit db4o nur noch die Objektorientierte gibt.
Sie denken nun sicherlich, ich bertreibe. Vielleicht! Aber verschaen Sie sich selbst einen berblick ber die Funktionalitten und lesen Sie dieses Buch. Sie brauchen keine zwei Welten mehr,
die sich eigentlich nicht mgen. Ich werde Ihnen anhand bekannter relationaler Datenbankfunktionalitten erklren, wie Sie nun mit einer neuen Objektorientierten arbeiten knnen. Es ist
mein Ziel, Ihnen die Einfachheit von db4o nahe zu bringen und gleichzeitig lieben zu lernen.
Bereits in den frhen 90 ger Jahre wurde damit begonnen, objektorientierte Datenbanken zu
entwickeln, aber erst mit db4o konnte im Jahre 2004 eine konkurrenzfhige Entwicklung auf den
Markt gebracht werden. Gegrndet im Jahre 2000 durch Carl Rosenberger schate es db4o innerhalb krzester Zeit, eine der wichtigsten Entwicklungen der letzten Jahre zu werden. So zhlen
heute Bosch, BMW, Hertz, Boeing und Intel zu dem immer grer werdenden Kundenstamm.

1.1 Fr wen ist dieses Buch?


Grundstzlich richtet sich dieses Buch an den Java-Programmierer mit Grundkenntnissen in
HTML und CSS, der sich in die objektorientierte Datenbank db4o anhand eines konkreten J2EEProjektes einarbeiten will, und zwar mithilfe eines Content-Management-Systems. Dieses Buch
ist sowohl fr den unbedarften Datenbankneuling als auch fr den erfahrenen Datenbankexperten
gedacht, der sich mit relationalen Datenbanken auskennt.

1.2 Wie geht dieses Buch vor?


Mit diesem Buch sollen die Grundlagen geschaen werden, um mit J2EE und db4o eine internetbasierte Datenbankanwendung zu erstellen, wobei allerdings der Schwerpunkt auf db4o liegen
soll. J2EE stellt nur den Rahmen fr db4o dar. Umgesetzt wird unser Projekt mit der Entwicklungsumgebung NetBeans. Es wird abwechselnd Wissen ber Servlets und JSPs und ber die Datenbank db4o vermittelt. db4o wird in ein J2EE-Projekt eingebunden, das auf dem Konzept des
Model-View-Controllers basiert, das die Trennung von Datenbankentwurf, Datenbankabfragen,
Programmierlogik und Darstellung im Internet beschreibt. Dieses Content-Management-System
stellt selbstverstndlich nur ein grobes Gerst dar. Der Leser soll angeregt werden, dieses Projekt
an seine eigenen Bedrfnisse anzupassen oder auf andere Zusammenhnge zu bertragen.
Da dieses Buch auch an Datenbankexperten gerichtet ist, die bereits auf jahrelange Erfahrung
mit relationalen Datenbanken zurckgreifen knnen, wird ein Vergleich gezogen zu bereits existierenden relationalen Konzepten. Fr diese Programmierer prallen die Welten der Objekte und
der Tabellen aufeinander und es ist eine Neuorientierung notwendig.

1 Einleitung

Sie nden unter www.db4o.com unter Projekts und Educational Projekts die Dateien fr das
Projekt dieses Buches, das in einzelnen Schritten in den folgenden Kapiteln erlutert wird. Es
gibt Ordner fr jedes einzelne Kapitel, z. B. Kap02 und Ordner, die zum Gesamtprojekt gehren.

1.3 ber NetBeans


Realisiert wird unser Web-Projekt mit NetBeans. NetBeans ist ein OpenSource-Projekt, das
von Sun Microsystems im Jahre 2000 gegrndet wurde und aus einem Studienprojekt hervorging. NetBeans ist eine Entwicklungsumgebung, die eine groe Hilfe beim Programmieren von
J2EE-Projekten darstellt. So sind z. B. in NetBeans bereits mehrere Frameworks und der WebContainer Tomcat integriert. Auerdem ist NetBeans ein Quelltexteditor, der Ihnen bei Syntaxund Tippfehlern hilft und ein umfangreiches Repertoire an Programmiervorschlgen (Code Completion) zur Verfgung stellt. Die in diesem Buch verwendete Entwicklungsumgebung ist NetBeans 5.5, Java 1.4 und Java 5.0.

1.3.1 Installation von NetBeans


Sie knnen NetBeans 5.5 oder hher von der Seite www.netbeans.org herunterladen. Doppelklicken Sie auf die heruntergeladene Datei und folgen Sie dem Installationsvorgang, der nach der
vorhandenen Java-Version sucht.

Abbildung 1.1: Installation von NetBeans

1.4 ber db4o


db4o ist eine Open-Source-Datenbank, die unter einer dualen Lizenz angeboten wird, ebenso wie
MySQL. So ist sie fr den kommerziellen Gebrauch kostenpichtig und fr die private Nutzung
frei, unter den Bedingungen der GPL.
Wo knnen Sie db4o herunterladen? Auf der Website www.db4o.de. Mit der Datenbank laden Sie
gleichzeitig verschiedene Dokumentationen herunter: In der in diesem Buch verwendeten Version
6.1 nden Sie eine HTML-Referenz, eine Api und eine PDF-Dokumentation. Auf der Website

1.4 ber db4o

gibt es auch eine ausfhrliche Linklist zu Themen rund um die Objektorientierung und objektorientierte Datenbanken und ein Forum fr Ihre Fragen. Sollten Sie zustzliche Informationen
suchen, nden Sie im Anhang ein Literaturverzeichnis und eine Linklist.

1.4.1 Wo ndet db4o Verwendung?


Ursprnglich wurde db4o fr den Einsatz in Standalone-Clients, wie z. B. Handys, entwickelt.
db4o eignet sich hervorragend fr alle Anwendungen, bei denen kein Datenbank-Administrator
notwendig ist. Neben dem eingebetteten Modus existiert aber auch ein Client-Server-Modus, der
es Ihnen ermglicht db4o in eine Client-Server-Umgebung zu integrieren.
Welche Projekte wurden bereits mit db4o realisiert? Hier einige der Erfolgsgeschichten der Datenbank db4o:
1. db4o steuert den Verpackungsroboter der Sigpack International AG (www.sigpack.com)
einer Tochtergesellschaft von BOSCH. Dieser Roboter stellt an Geschwindigkeit alles bisher
Dagewesene in den Schatten.
2. Das fhrende spanische IT-Unternehmen Indra Sistemas (www.indra.es) verwendet db4o
als Herzstck des Kontrollsystems des neuen AVEs in Spanien. AVE ist ein neuer Hochgeschwindigkeitszug, der in Zukunft alle wichtigen spanischen Stdte mit Madrid in weniger
als 4 Stunden verbinden soll.
3. db4o ist Teil einer Software fr Smartphones mit Namen Mandala Notebook. Hersteller
dieser Software ist Mandala IT (www.mandalait.com) ein kleines Start-Up-Unternehmen
der IT-Branche. Diese Software erlaubt es u. a. dem Benutzer von seinem Handy, WordDateien oder Bilder zu importieren oder zu exportieren.
4. Am Institut fr Geoinformatik der Universitt Mnster (http:\\ifgi.uni-muenster.de\) wird
db4o in einer internetbasierten Anwendung fr geochemische Daten verwendet.
5. An der spanischen Universitt von Lleida wird db4o fr ein archologisches Dokumentationssystem verwendet, das mit Swing umgesetzt wurde.
Dies war nur eine kleine Auswahl der vielen bereits mit db4o realisierten Projekte, aber sie
zeigen alle Eines: die hohe Leistungsfhigkeit und vielseitige Einsetzbarkeit von db4o. Mehr
Informationen zu den Projekten und Kunden von db4o nden Sie auf der Website www.db4o.com
unter der Rubrik About und Customers.

1.4.2 Performance
Schnelligkeit stellt fr jede Datenbank eine hohe Herausforderung dar. Diese hat db4o in all
seinen Projekten unter Beweis gestellt. Des Weiteren gibt es eine Open-Source-Initiative PolePosition (www.polepos.org) unter dem Dach von www.sourceforge.net, die verschiedene Tests zum
Vergleich von Geschwindigkeiten entwickelt hat. Fast alle Tests zeigen hierbei eine berlegenheit
von db4o gegenber Hibernate und MySQL. Wobei sich allerdings folgende Einschrnkungen
formulieren lassen: Erstens kann die Kombination JDBC\HSQLDB db4o im Geschwindigkeitstest bertrumpfen. Und zweitens je acher die Objekte desto besser schneidet die Kombination
SQL\JDBC ab und bertrit db4o. Suchen Sie hierzu nhere Informationen, nden Sie sie bei
www.db4o.com unter der Kategorie About, Product Information und Benchmarks.

1 Einleitung

Anzahl der gleichzeitig mglichen Zugrie


Bei der Planung eines Web-Projektes mit db4o gilt es allerdings eine Einschrnkung zu beachten:
Die Anzahl gleichzeitig zugreifender Benutzer ist begrenzt. Es sind nur 5-10 Requests pro Sekunde
mglich, dies entspricht einer Anzahl von Datenbankabfragen von bis zu 600 pro Minute.
Wie lassen sich diese Probleme entzerren oder lsen? Wie knnen Spitzenzeiten abgefangen werden? Wir werden im Verlaufe dieses Buches sehen, wie sich eine Webanwendung durch verschiedene Strategien optimieren lsst: Erstens werden Daten normalisiert und wieder denormalisiert.
Zweitens knnen Daten auf verschiedene Datenbanken aufgeteilt werden. Drittens gibt es Vorgehensweisen, Lockingvorgnge sinnvoll einzusetzen. Und last, but not least stellt db4o einen
eigenen Arbeitsspeicher zur Verfgung.

1.4.3 Ausblick
Die objektorientierte Datenbank stellt eine der interessantesten Entwicklungen in der EDV der
letzten Jahre dar. Es wurden neue Wege beschritten, die noch lange nicht zu Ende sind. db4o
ist ein OpenSource-Projekt, das von vielen Seiten beeinusst wird und sich im stndigen Fluss
bendet. Es gibt viele Ideen, die im Moment nur angedacht sind, aber denen eine groe Zukunft
bevorsteht. Beobachten Sie mit mir die Entwicklungen, die db4o noch nehmen wird.

2 Einstieg in unser Projekt

2.1 Das erste J2EE-Projekt in NetBeans


Beginnen wir mit dem ersten Schritt auf dem Weg zu unserem Content-Management-System.
Wir erstellen unser erstes Projekt in NetBeans, ein Web-Projekt, das das Grundgerst darstellt
fr all unsere Dateien. Genauere Informationen zu der Ordnerstruktur in Web-Projekte nden
Sie weiter hinten im Kapitel Einstieg in J2EE.
Gehen Sie bitte wie folgt vor:

1. nen Sie NetBeans.

2. Klicken Sie im Men auf File und dann auf New Project.

Abbildung 2.1: Neues Projekt

3. Whlen Sie Web und auf der rechten Seite Web Application aus und gehen Sie mit Next
weiter zum nchsten Schritt.

2 Einstieg in unser Projekt

Abbildung 2.2: 1.Schritt: Choose Project

4. Vergeben Sie den Namen DasErsteProjekt und legen Sie den Ordner fest, in dem Ihr Projekt
abgespeichert werden soll: C:/Datenbank.

Abbildung 2.3: 2.Schritt: Name and Location

5. Im nchsten Schritt besteht die Mglichkeit, sowohl die Frameworks Struts als auch Java
Server Faces einzubinden.

2.2 Installation von db4o:Einbinden einer Bibliothek

Abbildung 2.4: 3.Schritt: Frameworks

6. Klicken Sie auf Finish.


NetBeans hat Ihnen auf diesem Weg bereits die gesamte Ordnerstruktur des Web-Projektes vorgegeben, die Sie jetzt nur noch mit Inhalt fllen mssen. Struts und Java Server Faces, sind
Frameworks, die zustzliche Funktionalitten zur Verfgung stellen, Web-Projekte zu vereinfachen und zu optimieren. Der im Kapitel Einstieg in J2EE vorgestellte Model-View-Controller
stellt die Basis von Struts dar.
Wollen Sie ein ganzes, bereits existierendes Projekt verwenden, mssen Sie im Men File, Open
Project nehmen und nicht den Unterpunkt New Project.

2.2 Installation von db4o:Einbinden einer Bibliothek


Machen wir weiter mit dem nchsten Schritt: Wir installieren db4o. Schon hier wird der Unterschied zu einer relationalen Datenbank deutlich: Beim Installationsvorgang wird nur die db4oBibliothek zu einem Projekt hinzugefgt und schon knnen Sie alle Funktionalitten von db4o
nutzen. Es wird nur - wie bei einem Framework - eine Bibliothek eingebunden.
Folgende Schritte sind notwendig, um die db4o-Bibliothek einzubinden:
1. Laden Sie die neueste Version db4o von der Website www.db4o.de herunter und entzippen
Sie sie in einem Verzeichnis Ihrer Wahl. Im Unterverzeichnis lib benden sich die Bibliotheken fr die jeweiligen Java-Versionen, wobei 5 sowohl 1.4 als auch 5 untersttzt.
2. Erstellen Sie im Ordner web/WEB-INF (vgl. hierzu Projektstruktur eines Web-Projektes
im Kapitel Einstieg in J2EE) ein Verzeichnis lib, in das Sie die db4o-Bibliothek kopieren.
3. Sie mssen zustzlich die Bibliothek dem NetBeans-Projekt hinzufgen: Klicken Sie das
Projekt mit der rechten Maustaste an, whlen Sie anschlieend Properties aus.

2 Einstieg in unser Projekt

Abbildung 2.5: Properties

4. Sie gelangen zu einem Fenster, das Ihnen auf der linken Seite verschiedene Kategorien
vorgibt, klicken Sie Libraries an und dann den Button Add JAR/Folder.

Abbildung 2.6: Bibliotheken (Libraries)

War das nicht einfach? Eine Datenbankinstallation in 5 Minuten. Keine komplizierten Installationsschritte, einfach nur eine Bibliothek hinzufgen und schon knnen Sie loslegen. Haben
Sie alles richtig gemacht, erscheint die db4o-Bibliothek in dem Ordner Libraries in der Ansicht
Projects.

2.2 Installation von db4o:Einbinden einer Bibliothek

Abbildung 2.7: Bibliotheken eines Projektes in NetBeans

3 Erste Datenbankabfragen in db4o

3.1 Erste berlegungen zu einem Datenbankentwurf: Unser erstes


Objekt
Wir beginnen mit einem einfachen Beispiel: Wir wollen alle CSS-Formatierungen unseres ContentManagement-Systems in db4o speichern. Fr jede Schriftfarbe und Schriftgre in unseren HTMLSeiten wollen wir ein separates CSS-Format festlegen. Wie gehen Sie in relationalen Datenbanksystemen vor? Sie erstellen eine Tabelle. Wie gehen Sie in einer objektorientierten Datenbank
vor? Sie erstellen eine Klasse.
Eine Klasse stellt in objektorientierten Programmiersprachen eine Art Prototyp dar. Ich mache
mir Gedanken welche Eigenschaften meine Klasse braucht und erstelle anschlieend davon nur
noch Kopien. Die Kopien werden Objekte oder Instanzen genannt.
Wir erstellen eine Klasse fr all unsere CSS-Formatierungen, die nur eine einzige Variable enthlt,
nmlich die Variable name. Die Variable name deklarieren wir als private, deshalb kann von
auerhalb der Klasse nicht direkt auf sie zugegrien werden. Wollen wir den Wert der Variablen
verndern oder wieder auslesen, mssen wir die Variablen mit Getter- und Setter-Methoden von
auen wieder zugnglich machen. Diese Art auf Variablen zuzugreifen, nennt man Kapselung.
Kapselung ist ein wichtiges Prinzip in der Objektorientierten Programmierung.
Des Weiteren besitzt unsere Klasse FormatierungEinfach zwei Konstruktoren: einen Standardkonstruktor und einen Konstruktor mit dem Parameter name. Welche Funktion hat ein Konstruktor? Er macht es Ihnen mglich eine Instanz einer Klasse zu erstellen. Er konstruiert also
ein Objekt.
Die Klasse FormatierungEinfach.java ist der erste Baustein fr unser Content-ManagementSystem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package Datenbankentwurf;
public class FormatierungEinfach {
private String name;
//Standardkonstruktor
public FormatierungEinfach(){
this.name = name;
}
//Konstruktor mit Parameter name
public FormatierungEinfach(String name) {
this.name = name;
}
public String getName() {
return name;

11

3 Erste Datenbankabfragen in db4o

19
20
21
22
23
24
25

public void setName(String name) {


this.name = name;
}
}

Listing 3.1: Klasse fr CSS-Formate

Ein Tipp: Getter- und Setter-Methoden knnen Sie in NetBeans erstellen, indem Sie folgende
Schritte ausfhren:

1. Klicken Sie auf die Variable name mit der rechten Maustaste und whlen Sie Refactor und
Encapsulate Fields aus

Abbildung 3.1: Refactoring und Encapsulating Fields

2. und im nchsten Schritt klicken Sie auf Next

12

3.1 Erste berlegungen zu einem Datenbankentwurf: Unser erstes Objekt

Abbildung 3.2: Button Next anklicken

3. und zum Schlu links unten auf Do Refactoring.

Abbildung 3.3: Do Refactoring anklicken

Lassen Sie uns einige erste Vergleiche mit relationalen Datenbanken ziehen: Unserer Klasse FormatierungEinfach entspricht unten stehender Tabelle FormatierungEinfach in einem relationalen
Datenbankentwurf, die mit folgendem CREATE-TABLE-Befehl, den Sie aus SQL kennen, erstellt
wird:
CREATE TABLE F o r m a t i e r u n g E i n f a c h

( ID

i n t e g e r PRIMARY KEY,

name

VARCHAR( 1 0 ) )
Sie stellen sich jetzt sicherlich die Frage: Wo ist in der Klasse FormatierungEinfach der Primrschlssel geblieben? Der Primrschlssel (PRIMARY KEY) erfllt in relationalen Datenbanksystemen die wichtige Aufgabe, einzelne Datenstze eindeutig zu identizieren. Jeder Datensatz

13

3 Erste Datenbankabfragen in db4o

besitzt einen anderen Schlssel und es gibt keinen Primrschlssel doppelt. So gibt es jede Rechnung mit der Nummer 1 oder jede Formatierung mit der Nummer 5 nur einmal.
Die Datenbank db4o vergibt auch fr jedes Objekt einen Schlssel, der sich Unique Object
Identier oder abgekrzt OID nennt, dieser ist aber fr den Datenbankprogrammierer nicht
sichtbar. Im Gegensatz zu relationalen Datenbanken legen nicht Sie den Schlssel fest, sondern die
Datenbank. Speichern Sie zwei Objekte der Klasse FormatierungEinfach mit gleichem Inhalt in
der Datenbank, gibt es in der Datenbank zwei Objekte mit gleichem Inhalt, aber unterschiedlichen
OIDs. Der Inhalt der Objekte ist gleich, aber nicht ihre OIDs. So gilt es immer sicherzustellen,
dass keine zwei Objekte mit gleichem Inhalt in der Datenbank existieren und Sie auch immer auf
das gleiche Objekt zugreifen.
Diese Fragestellung wird uns im Weiteren immer wieder beschftigen. Ihnen wird es sicherlich am
Anfang schwerfallen, sich an den Gedanken zu gewhnen, ohne sichtbaren Primrschlssel und
ohne Tabellen zu arbeiten, aber am Ende dieses Buches wird es Ihnen aus objektorientierter Sicht
viel logischer und einfacher vorkommen. Es entspricht der objektorientierten Denkweise, Objekte direkt in der Datenbank zu speichern, und es stellt eine Arbeitserleichterung zu bisherigen
relationalen Vorgehensweisen dar.

3.2 Wichtige Klassen und Interfaces

3.2.1 Das Package com.db4o


Wo nden Sie die wichtigsten Methoden fr unsere ersten Datenbankabfragen? Im Package
com.db4o, das aus drei Interfaces und einer Klasse besteht. Hier ein Ausschnitt aus der db4o-API:

Abbildung 3.4: Das Package com.db4o

Im Moment wollen wir uns auf die Methoden des so genannten Solo-Modus konzentrieren und
uns erst spter mit dem Client-Server-Modus beschftigen. Das Interface ObjectContainer stellt
Ihnen die passenden Methoden fr einfache Datenbankabfragen sowohl im Stand-Alone-Modus
als auch im Client-Server-Modus zur Verfgung. So enthlt es z. B. folgende Methoden:

14

1.

set(): speichert ein Objekt

2.

get(): liest ein Objekt wieder aus

3.2 Wichtige Klassen und Interfaces

3.

get() und set(): zuerst wird das zu verndernde Objekt ausgelesen und anschlieend wird
es gendert

4.

get() und delete(): liest Objekt aus und lscht es

5.

close(): schliet die Datenbank wieder

In der Klasse Db4o gibt es die Methode openFile(), die die Datenbank net und der Sie den
Namen der Datenbank als Parameter bergeben.
Ein ObjectSet stellt eine Aufzhlung aller Abfrageergebnisse dar, hnlich einer ArrayList, das
mit den Methoden hasNext() und next() ausgelesen wird.

3.2.2 Das Interface ExtObjectContainer


Ein Subinterface des Interfaces ObjectContainer ist das Interface ExtObjectContainer, das sich
im Package com.db4o.ext bendet. Hier wieder ein Ausschnitt aus der db4o-API:

Abbildung 3.5: Das Interface ExtObjectContainer

Dieses Interface stellt ergnzende Methoden zum Interface ObjectContainer zur Verfgung. So
gibt es folgende wichtige Methode:
getID ( java . lang . Object

obj )

die long als Rckgabetyp hat und den OID zurckgibt. Der OID ist eine interne Zahl, die es
innerhalb der Datenbank nur einmal gibt und die jedem Objekt zugewiesen wird.
Benden Sie sich in einem ObjectContainer, mssen Sie zuerst einen Cast durchfhren, der einen
ObjectContainer in einen ExtObjectContainer verwandelt. Dies geschieht mit der Methode ext().
Die gesamte Befehlszeile lautet wie folgt:
long

i d = o b j e c t C o n t a i n e r . ext ( ) . getID ( java . lang . Object

obj )

15

3 Erste Datenbankabfragen in db4o

3.3 Datenbankabfragen

3.3.1 Speichern von Objekten


Wie wird unser soeben erstelltes Objekt gespeichert? Zuerst muss ein ObjectContainer und
die zugehrige Datenbank genet werden. Sollte die Datenbank noch nicht existieren, wird
automatisch eine erstellt. Die Datenbank erhlt die Endung .yap, die fr "yet another protocol"
steht. Der Name wurde nicht vergeben, weil er eine bestimmte Bedeutung besitzt, sondern weil es
ihn noch nicht gibt  soweit bekannt. Da die Datenbankverbindung unterbrochen werden kann,
solange Daten gespeichert werden, muss dieser Vorgang in einem try-catch-nally-Block stehen.
Dieser macht es mglich, Probleme aufzufangen, ohne dass das Programm abgebrochen wird.
Der try-catch-nally-Block besteht aus drei Teilen: Im try-Block steht die Methode, die ein
Objekt in der Datenbank speichert, nmlich set(); es wird also versucht das Objekt in der
Datenbank zu speichern. Der catch-Block gibt im Falle eines Problems eine Fehlermeldung aus.
Ein eventueller Fehler wird also aufgefangen. Zum Schluss wird der nally-Block auf jeden Fall
durchgefhrt und schliet die Datenbank wieder.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

16

package Kap03;
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ext.DatabaseFileLockedException;

public class FormatierungDatenSpeichern {


public void speichern(FormatierungEinfach f){
//ffnen der Datenbank
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
/*Es wird versucht (try) der Datenbank das Objekt f
*hinzufgen (set),*/
try {
db.set(f);
/*und sollte es Probleme beim ffnen der Datenbank
oder beim Abspeichern des Objektes geben,
wird eine Exception (DatabaseFileLockedException)
geworfen; sie wird im catch-Block aufgefangen
und es kommt zur Ausgabe einer Fehlermeldung.*/
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
/*Der finally-Block wird auf jeden Fall durchgefhrt,
so wird die Datenbank wieder geschlossen (close).*/
} finally{
db.close();

3.3 Datenbankabfragen

34
35
36

Listing 3.2: Speichern eines Formatierungsobjektes


Kommen wir wieder zu SQL zurck und schauen uns an, wie Formatierungen in einer relationalen Datenbank gespeichert werden. Eine neue CSS-Formatierung wird mit dem INSERT-Befehl
gespeichert und er lautet:
INSERT INTO F o r m a t i e r u n g E i n f a c h VALUES( 1 ,

" font1 ")

3.3.2 Auslesen von Objekten mit Query-by-Example


Wie wird das gespeicherte Objekt wieder ausgelesen? Mit einem Beispielobjekt und der Methode get(). Dieser Vorgang nennt sich Query-by-Example und stellt eines der Abfragekonzepte in
db4o dar (vgl. Kapitel Abfragekonzepte). In unserem Falle wollen wir alle FormatierungEinfachObjekte aus der Datenbank auslesen: Wir erstellen ein Beispielobjekt, indem wir dem Konstruktor den Default-Wert (Standardwert) eines Objektes bergeben, nmlich null. So lautet die
entsprechende Befehlszeile:
FormatierungEinfach

f o = new

FormatierungEinfach ( n u l l ) ;

Wrde die Klasse statt einem String einen primitiven Datentyp enthalten, wie z. B. eine Variable vom Datentyp int, ist der Default-Wert 0 und dieser msste dem Beispielobjekt bergeben
werden. Bei den primitiven Datentypen oat lautet der Standardwert 0.0F oder bei double 0.0D.
Wir erhalten als Ergebnis der Abfrage ein Objekt vom Typ ObjectSet zurck, das alle vorhandenen FormatierungEinfach-Objekte enthlt. Wir legen das ObjectSet als ein generisches ObjectSet fest (ObjectSet<FormatierungEinfach>), so werden beim Auslesen FormatierungEinfachObjekte zurckgegeben und keine Objekte vom Typ Object. Die Methode hasNext() stellt fest,
ob das ObjectSet noch weitere Objekte enthlt und die Methode next() liest die Objekte aus.
Alle FormatierungEinfach-Objekte werden anschlieend einer generischen ArrayList hinzugefgt
und die ArrayList wird von der Methode auslesen() zurckgegeben.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package Kap03;
import
import
import
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;
java.util.Collection;

public class FormatierungDatenAuslesen {


/*Die Methode auslesen() gibt eine generische ArrayList zurck. */
public ArrayList<FormatierungEinfach> auslesen(){

17

3 Erste Datenbankabfragen in db4o

ObjectContainer db = Db4o.openFile("C:/Datenbank/DasErsteProjekt/datenbank.yap");

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

/*Instanziieren der generischen ArrayList, die Objekte der Klasse


FormatierungEinfach ein- und ausliest.*/
ArrayList<FormatierungEinfach> f = new ArrayList<FormatierungEinfach>();
try {
FormatierungEinfach fo = new FormatierungEinfach(null);
/*Die Methode get() liest die FormatierungEinfach-Objekte aus und gibt ein
ObjectSet zurck, das alle FormatierungEinfach-Objekte enthlt.*/
ObjectSet<FormatierungEinfach> result = db.get(fo);
/*hasNext() stellt fest, ob das ObjectSet noch weitere Elemente enthlt*/
while (result.hasNext()){
/*next() gibt die FormatierungEinfach-Objekte aus*/
fo = result.next();
/*Das FormatierungEinfach-Objekt, das aus der Datenbank
ausgelesen wurde, wird der generischen ArrayList hinzugefgt.*/
f.add(fo);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
/*Die Methode auslesen() gibt die ArrayList f zurck.*/
return f;
}
}
Listing 3.3: Auslesen von Formatierungsobjekten
Die Methode auslesen() gibt eine generische ArrayList zurck. Eine ArrayList ist eine Liste, die
mehrere Elemente beinhalten kann. Sie ist in der Regel die beste Implementierung aller Listen, da
sie einen sehr schnelle wahlfreien Zugri ermglicht und auf einem Array basiert, das dynamisch
schrumpft und wchst. Die Elemente einer Liste haben wie bei einem Array Felder und einen
Index. Die Reihenfolge der Ausgabe der Elemente ist identisch mit der Reihenfolge der Eingabe.
Generics wurden in Java mit 5.0 eingefhrt und bedeuten eine sinnvolle Erweiterungen, z. B. der
Funktionen einer ArrayList. Generisch bedeutet, eine ArrayList, der nur FormatierungEinfachObjekt hinzugefgt werden knnen, gibt auch nur FormatierungEinfach-Objekte zurck und
keine Objekte der Klasse Object. Eine generische ArrayList erspart Ihnen also das nachtrgliche
Casten von Objekten der Klasse Object in Objekte der Klasse FormatierungEinfach, da sie bereits
Objekte der Klasse FormatierungEinfach zurckgibt.

18

3.3 Datenbankabfragen

Sollten Sie allerdings Java 1.4 benutzen, steht Ihnen die Mglichkeit von generischen ArrayListen
nicht zur Verfgung. Dies hat zur Folge, dass eine ArrayList Objekte der Klasse Object zurckgibt, die in Objekte der Klasse FormatierungEinfach gecastet werden mssen. Und dies obwohl
der ArrayList Objekte der Klasse FormatierungEinfach hinzugefgt worden sind. Casten bedeutet, Objekte der Klasse Object mssen in Objekte der Klasse FormatierungEinfach umgewandelt
werden. Unten stehend das entsprechende Java Listing fr Java 1.4.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

package Kap03;
import
import
import
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;
java.util.Collection;

public class FormatierungDatenAuslesen14 {


/*Die Methode auslesen() gibt eine ArrayList zurck */
public ArrayList auslesen(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
/*Instanziieren der ArrayList, die Objekte der Klasse
Object und alle Kindklassen ein- und ausliest*/
ArrayList f = new ArrayList();
try {
FormatierungEinfach fo = new FormatierungEinfach(null);
/*Die Methode get() liest die FormatierungEinfach-Objekte
aus, und sie gibt ein Objekt der Klasse Object zurck, das
in ein Objekt der Klasse ObjectSet gecastet werden mu*/
ObjectSet result = (ObjectSet)db.get(fo);
/*hasNext() stellt fest, ob das ObjectSet noch weitere
Elemente enthlt*/
while (result.hasNext()){
/*next() gibt die FormatierungEinfach-Objekte aus, die
aber zuerst von einem Objekt der Klasse Object in ein
Objekt der Klasse FormatierungEinfach gecastet
werden muss*/
fo = (FormatierungEinfach)result.next();
/*Das FormatierungEinfach-Objekt, das aus der Datenbank

19

3 Erste Datenbankabfragen in db4o

43
44
45
46
47
48
49
50
51
52
53
54
55
56

ausgelesen wurde, wird der ArrayList hinzugefgt*/


f.add(fo);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

/*Die Methode auslesen() gibt die ArrayList f zurck*/


return f;

Listing 3.4: FormatierungDatenAuslesen14.java


Ziehen wir wieder den direkten Vergleich zu SQL: Alle CSS-Formatierungen werden mit dem
SELECT-Befehl aus einer relationalen Datenbank ausgelesen:
SELECT

FROM F o r m a t i e r u n g E i n f a c h

Es werden nicht immer alle FormatierungEinfach-Objekte bentigt, sondern nur Bestimmte.


Wie knnen Sie aus db4o ein genau deniertes Objekt auslesen? Instanziieren Sie ein Objekt mit
einem eindeutigen Wert: in unserem Fall mit der Variablen name. Wir erstellen also wieder ein
Beispielobjekt:
FormatierungEinfach

p = new

F o r m a t i e r u n g E i n f a c h ( name ) ;

Hier die dazu passende vollstndige Methode und Klasse:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

20

package Kap03;
import
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

public class FormatierungDatenAuslesenEinzeln {


public FormatierungEinfach auslesenEinzeln(String name){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
FormatierungEinfach fo = new FormatierungEinfach();
try {

3.3 Datenbankabfragen

20
21
22
23
24
25
26
27
28
29
30
31
32

FormatierungEinfach p = new FormatierungEinfach(name);


ObjectSet<FormatierungEinfach> result = db.get(p);
fo = result.next();
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return fo;

}
}

Listing 3.5: FormatierungDatenAuslesenEinzeln.java


In SQL ist dies natrlich auch mglich. Es wird eine bestimmte CSS-Formatierung, wie z. B.
font1, mit dem SQL-Befehl SELECT folgendermaen ausgelesen:
SELECT

FROM F o r m a t i e r u n g E i n f a c h WHERE name = " f o n t 1 "

3.3.3 Lschen von Objekten


Wir wollen die Objekte, die wir gespeichert haben, wieder lschen. Die entsprechende Methode
in db4o heit delete(). Sie bergeben ihr das Objekt als Parameter, das Sie lschen wollen. Bevor
Sie ein Objekt lschen knnen, mssen Sie es aus der Datenbank auslesen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package Kap03;
import
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

public class FormatierungDatenLoeschen {


public void loeschen(FormatierungEinfach f){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
/*Das zu lschende Objekt muss zuerst aus der
Datenbank ausgelesen werden.*/
ObjectSet<FormatierungEinfach> result = db.get(f);
FormatierungEinfach p = result.next();

21

3 Erste Datenbankabfragen in db4o

22
23
24
25
26
27
28
29
30
31
32

/*Die Methode delete() lscht Objekte wieder.*/


db.delete(p);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 3.6: Lschen eines bestimmten Objektes


In SQL heit der Befehl, der einen bestimmten Datensatz lscht, ebenfalls DELETE:
DELETE FROM F o r m a t i e r u n g E i n f a c h WHERE name = " f o n t 1 "

3.3.4 ndern von Objekten


Last, but not least, ndern wir ein Objekt. Wie geschieht dies? Sie mssen zuerst das entsprechende Objekt auslesen und dann mit der Methode setName() den Namen des Objektes ndern.
Wichtig: Diese beiden Vorgnge mssen durchgefhrt werden, solange die Datenbank oen ist.
Wollen Sie ein Objekt ndern, so bentigen Sie zwei Methoden. Sie stellen eine Einheit dar.
Sie drfen nicht zuerst die oben stehenden Methoden auslesenEinzeln() durchfhren und dann
die Methode speichern(), da dies dazu fhrt, dass das FormatierungEinfach-Objekt ein weiteres
Mal abgespeichert wird. Auf diese Art und Weise wird nicht dieses bestimmte Objekt verndert,
sondern ein Neues erstellt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

22

package Kap03;
import
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

public class FormatierungDatenAendern {


public void aendern(FormatierungEinfach f, FormatierungEinfach fo){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
/*Das zu verndernde Objekt wird aus der Datenbank mit der
Methode get() ausgelesen.*/

3.3 Datenbankabfragen

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

ObjectSet<FormatierungEinfach> result = db.get(f);


FormatierungEinfach p = result.next();
String name = fo.getName();
p.setName(name);
/*Das genderte Objekt wird wieder mit der Methode set() gespeichert.*/
db.set(p);
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
}
}
Listing 3.7: ndern eines bestimmten Objektes

Der entsprechende Befehl in SQL unterscheidet sich vom Prinzip her von der obigen Vorgehensweise. Die Methoden get() und set() entsprechen in SQL einem Befehl. Es wird in einem Schritt,
der zu verndernde Datensatz gesucht und verndert.
UPDATE F o r m a t i e r u n g E i n f a c h SET name = " f o n t 2 " WHERE name = " f o n t 1 "

3.3.5 Praktische Anwendungsbeispiele


Bis jetzt haben wir die entsprechenden Abfragen fr unsere Klasse FormatierungEinfach kennen
gelernt, lassen Sie uns diese nun ausprobieren. Zuerst speichern wir zwei FormatierungEinfachObjekte:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

package Kap03;
import Datenbankentwurf.FormatierungEinfach;
public class Einlesen {
public static void main(String[] args){
FormatierungDatenSpeichern fd = new FormatierungDatenSpeichern();
FormatierungEinfach f = new FormatierungEinfach("font1");
FormatierungEinfach fo = new FormatierungEinfach("font2");
fd.speichern(f);
fd.speichern(fo);
}

Listing 3.8: Einlesen.java

23

3 Erste Datenbankabfragen in db4o

Tipp: Eine Java-Klasse knnen Sie starten, indem Sie mit der rechten Maustaste in die JavaKlasse klicken und Run File auswhlen. Der entsprechende Short-Cut lautet Umschalt + F6.
Die Datenbank dantenbank.yap wird hierbei im Verzeichnis C:Datenbank/DasErsteProjekt angelegt. Wenn Sie die Datenbank nen, werden Sie feststellen, dass Sie nicht allzu viel mit dem
Inhalt anfangen knnen, da die Objekte als binre Daten gespeichert werden.

Abbildung 3.6: Unser Datenbank datenbank.yap

Anschlieend lesen wir alle Objekte wieder aus der Datenbank aus. Werden tatschlich beide
Elemente wieder ausgelesen? Ja, beide CSS-Formatierungen erscheinen auf der Konsole.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

package Kap03;
import Datenbankentwurf.FormatierungEinfach;
import java.util.ArrayList;
public class Auslesen {
public static void main(String[] args){
FormatierungDatenAuslesen fda = new FormatierungDatenAuslesen();
/*Die Methode auslesen() gibt eine generische ArrayList zurck,*/
ArrayList<FormatierungEinfach> al = fda.auslesen();
/*aus der direkt Objekte der Klasse FormatierungEinfach
mit der erweiterten for-Schleife ausgelesen werden.*/
for(FormatierungEinfach fo: al){
System.out.println("Auslesen Formatierung: "+fo.getName());
}
}

Listing 3.9: Auslesen.java

Ausgabe:
Auslesen Formatierung: font2
Auslesen Formatierung: font1

24

3.3 Datenbankabfragen

Weiter oben haben wir eine Methode auslesen() fr Java 1.4 erstellt, aus der wir in unten stehendem Listing wieder FormatierungEinfach-Objekte auslesen. Weil Java 1.4 noch nicht den
Konstrukt der erweiterten for-Schleife kannte, bentigen wir hierzu den Iterator. Der Iterator
liest keine Objekte der Klasse FormatierungEinfach aus, sondern Objekte der Klasse Object,
die anschlieend gecastet werden mssen. Die Objekte der Klasse Object mssen also wieder in
Objekte der Klasse FormatierungEinfach zurckgendert werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

package Kap03;
import Datenbankentwurf.FormatierungEinfach;
import java.util.ArrayList;
import java.util.Iterator;
public class Auslesen14 {
public static void main(String[] args){
FormatierungDatenAuslesen14 fda = new FormatierungDatenAuslesen14();
/*Die Methode auslesen() gibt eine ArrayList zurck,*/
ArrayList al = fda.auslesen();
/*die mit einer for-Schleife und dem Iterator ausgelesen wird,
wobei die Methode hasNext() feststellt, ob es noch weitere
Elemente in der ArrayList gibt.*/
for(Iterator iter = al.iterator(); iter.hasNext();){
/*Es werden Objekte der Klasse Object zurckgegeben,*/
Object o = iter.next();
/*die in FormatierungEinfach-Objekte gecastet (umgewandelt)
werden mssen.*/
FormatierungEinfach fo = (FormatierungEinfach)o;
System.out.println("Auslesen Formatierung: "+fo.getName());

Listing 3.10: Auslesen14.java


Nehmen wir nun an, Sie brauchen nicht alle FormatierungEinfach-Objekte, sondern nur ein Bestimmtes. Hierzu nehmen wir die Methode auslesenEinzeln() und lesen nur das Objekt mit dem
Namen font1 aus, und Sie erhalten das gewnschte Ergebnis:

1
2
3

package Kap03;
import Datenbankentwurf.FormatierungEinfach;

25

3 Erste Datenbankabfragen in db4o

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import java.util.ArrayList;
public class AuslesenEinzeln {
public static void main(String[] args){
FormatierungDatenAuslesenEinzeln fda =
new FormatierungDatenAuslesenEinzeln();
FormatierungEinfach fo = fda.auslesenEinzeln("font1");
System.out.println("Auslesen Formatierung: "+fo.getName());
}

Listing 3.11: AuslesenEinzeln.java

Ausgabe:
Auslesen Formatierung: font1
Sollten Sie ein Element auslesen wollen, dass es nicht gibt, wird eine NullPointerException geworfen:

Ausgabe:
Exception in thread "main" java.lang.NullPointerException
at Kap02.AuslesenEinzeln.main(AuslesenEinzeln.java:14)
Java Result: 1
Als Nchstes wollen wir den Namen einer CSS-Formatierung ndern, wir benennen ein FormatierungEinfachObjekt mit dem Namen font1 in font3 um:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

26

package Kap03;
import Datenbankentwurf.FormatierungEinfach;
public class Aendern {
public static void main(String[] args){
FormatierungDatenAendern fd = new FormatierungDatenAendern();
FormatierungEinfach f = new FormatierungEinfach("font1");
FormatierungEinfach fo = new FormatierungEinfach("font3");
fd.aendern(f, fo);

3.4 Zusammenfassende erste berlegungen

15
16
17

Listing 3.12: Aendern.java


Lesen wir nun wieder mit Auslesen.java unsere Daten aus, erhalten wir folgende Ausgabe auf der
Konsole:
Auslesen Formatierung: font2
Auslesen Formatierung: font3
Wie einfach! Alles funktioniert so wie wir es uns gedacht hatten. So bleibt uns nur noch auszuprobieren, ob sich die Objekte auch so einfach wieder lschen lassen. Wir lschen in unten
stehender Klasse font2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

package Kap03;
import Datenbankentwurf.FormatierungEinfach;
public class Loeschen {
public static void main(String[] args){
FormatierungDatenLoeschen fl = new FormatierungDatenLoeschen();
FormatierungEinfach f = new FormatierungEinfach("font2");
fl.loeschen(f);
}

Listing 3.13: Loeschen.java


Und tatschlich die CSS-Formatierung font2 wurde gelscht, wie wir es zweifelsohne erwartet
haben und es wird nur noch das FormatierungEinfach-Objekt mit Namen font3 ausgegeben:
Auslesen Formatierung: font3
Dies waren unsere ersten kleinen Gehversuche mit der objektorientierten Datenbank db4o. Bisher
ist uns alles problemlos gelungen. So knnen wir uns gut gerstet im nchsten Kapitel an das
weitere Datenbankdesign machen.

3.4 Zusammenfassende erste berlegungen


Es ist tatschlich so leicht: Sie nehmen die Objekte und speichern Sie in der Datenbank. db4o ist
eine echte objektorientierte Datenbank, die es Ihnen ermglicht Objekte direkt in der Datenbank

27

3 Erste Datenbankabfragen in db4o

zu speichern, ohne sie vorher in eine relationale Struktur bringen zu mssen. Oder: Ohne vorher
die Objekte mithilfe von Hibernate mappen zu mssen. Es fllt das komplette relationale Design
weg, da die Objekte bereits das Datenbankschema darstellen. Dies spart Entwicklungszeit und
somit viel Geld. Produkte knnen so frher zur Marktreife gebracht werden.
Fazit: Keine relationale Datenbank, kein relationales Mapping ist ntig. Sie knnen sich ganz auf
Ihre Objekte konzentrieren.

28

4 Ideen zu einem objektorientierten


Datenbankentwurf

4.1 berlegungen
Wie geht es nun weiter mit unserer Datenbank? Wir haben bereits den ersten Bestandteil unserer
Datenbank: unten stehende Klasse FormatierungEinfach, die wir aus dem vorangegangen Kapitel
kennen. Was ist, wenn wir weitere Elemente integrieren wollen und komplexere Zusammenhnge
darstellen wollen?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

package Datenbankentwurf;
public class FormatierungEinfach {
private String name;
//Standardkonstruktor
public FormatierungEinfach(){
this.name = name;
}
//Konstruktor mit Parameter name
public FormatierungEinfach(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Listing 4.1: FormatierungEinfach.java

Die Klasse FormatierungEinfach soll den Ausgangspunkt fr weitere berlegungen darstellen:


Welche zustzlichen Elemente brauchen wir fr eine Webseite? Was macht unsere Website zu
einer Website? Texte, Bilder, Hyperlinks und Verlinkungen zu PDFs. Also brauchen wir fr jedes
genannte Element eine separate Klasse: eine Klasse Text, Bild, Link und PDF. Zustzlich bentigen wir noch eine Klasse WebSite als zusammenfassende Klasse. Beginnen wir mit der Klasse

29

4 Ideen zu einem objektorientierten Datenbankentwurf

Bild, die aus dem Pfad und einem Namen besteht. Der Name erscheint in einer HTML-Seite
anstelle eines Bildes, wenn dieses nicht gefunden wird und der Pfad entspricht dem Speicherort
des Bildes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

package Datenbankentwurf;
public class Bild {
private String name;
private String pfad;
public Bild (){
}
public Bild(String name, String pfad) {
this.name = name;
this.pfad = pfad;
}
public String getPfad() {
return pfad;
}
public void setPfad(String pfad) {
this.pfad = pfad;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Listing 4.2: Bild.java

4.2 Theoretische Grundlagen


ber dreiig Jahre Erfahrung in der Entwicklung von relationalen Datenbanken haben viel Wissen und Theorie hervorgebracht. Diese Theorie wollen wir uns ansehen und dann im Folgenden
berlegen, wie diese Theorie auf objektorientierte Datenbanken bertragen werden kann oder
tatschlich bertragen wird. Diese Vorgehensweise stellt eine Krcke dar, da es nur unzureichende theoretische Grundlagen fr objektorientierte Datenbanken gibt. In der Welt der objektorientierten Datenbanken wird also versucht, Prinzipien aus der relationalen Datenbankwelt zu

30

4.2 Theoretische Grundlagen

bertragen und zu erweitern. So erfordert das Einbinden der objektorientierten Datenbank db4o
in ein Web-Projekt auf der einen Seite analoges Vorgehen zu dem Einbinden von relationalen
Datenbanken, aber auf der anderen Seite auch kreatives Denken von neuen Lsungen.

4.2.1 Datenredundanz und Normalisierung


Was verstehen wir unter Redundanz? Redundante Daten sind Daten, die in einer Datenbank
mehrmals vorkommen knnen. hnlich wie bei relationalen Datenbanken, mssen redundante
Daten vermieden werden. So ist es nicht sinnvoll, jedes Mal den Artikel Computer anzulegen,
wenn Sie eine neue Rechnung schreiben wollen. Dies htte drei Nachteile: Erstens wrde dies die
Zeit, die Sie zur Dateneingabe bentigen, enorm vervielfachen. Zweitens wrden die Fehlerquellen
zunehmen und das Risiko, statt einem Artikel zum Schlu jede Menge Artikel zu haben. Warum
mehrere Artikel? Da die Mglichkeit sich zu vertippen doch relativ gro ist und sich jeder Artikel
dann nur durch eine Kleinigkeit vom Anderen unterscheidet. Und drittens wrde Ihre Datenbank
explodieren und langfristig viel zu gro werden.
Um redundante Daten zu verhindern, werden in relationalen Datenbanksystemen Tabellen normalisiert, d. h. die Daten werden solange auf mehrere Tabellen verteilt, bis sichergestellt wird,
dass alle Daten in einer Datenbank nur ein einziges Mal vorhanden sind. Anschlieend werden die
Daten wieder mithilfe von Primr- und Fremdschlsseln miteinander verbunden. Primrschlssel
haben die Aufgabe, Daten eindeutig zu identizieren, d. h. es gibt jede Formatierung mit der
Nummer 1 nur ein einziges Mal. So knnen Sie diesen Schlssel in eine andere Tabelle eintragen
und schon gibt es eine Beziehung zwischen den beiden Tabellen. So hat der Primrschlssel in
der andere Tabelle die Funktion eines Fremdschlssels bernommen.
Gibt es Situationen, in denen es sinnig ist, die Normalisierung zum Teil wieder rckgngig zu
machen? Ja! Nehmen Sie folgenden Fall: Es greifen viele Personen auf Ihre Website zu und es
knnte zu Verzgerungen bei den Antwortzeiten kommen. Der Vorgang die Normalisierung ganz
oder teilweise wieder rckgngig zu machen, wird Denormalisierung genannt. Wir werden uns
weiter unten darber noch Gedanken machen.
Datenbankexperten, die mit relationalen Datenbanken bestens vertraut sind, wird am Anfang
vieles neu und spanisch vorkommen, und sie werden einige Zeit brauchen, sich an das objektorientierte Konzept von db4o zu gewhnen. Aber glauben Sie mir nach Anfangsschwierigkeiten,
werden Sie db4o lieben.

4.2.2 Das Entity-Relationship-Modell


Da es in objektorientierten Datenbanken keine Tabellen gibt, werden wir zur Beschreibung der
Datenbank das Entity-Relationship-Modell zu Hilfe nehmen, um einen Datenbankentwurf ohne
Redundanzen zu erhalten. Im Entity-Relationship-Modell gibt es verschiedene Beziehungen, die
wir im nchsten Kapitel anhand von konkreten Beispielen nher betrachten werden:
1.

1:1-Beziehung: Ein Objekt wird genau einem anderen Objektyp zugeordnet.

2.

1:n-Beziehung: Ein Objekt wird mehreren Objekten eines anderen Objekttyps zugeordnet.

3.

m:n-Beziehung: Sowohl dem ersten Objekttyp werden mehrere Objekte des zweiten Objekttyps zugeordnet als auch umgekehrt.

31

4 Ideen zu einem objektorientierten Datenbankentwurf

4.2.3 Referentielle Integritt


Was versteht man unter Referentieller Integritt? Referentielle Integritt umfasst zwei Aspekte:
Der erste Aspekt beinhaltet, dass Sie in eine Rechnung keinen Artikel eingeben knnen, der in
der Datenbank nicht vorhanden ist. So mssen Sie also zuerst einen Artikel anlegen, bevor Sie
fr diesen Artikel eine Rechnung schreiben knnen.
Der zweite Aspekt betrit den Lschvorgang: So kann es unmglich gemacht werden, z. B. eine
Rechnung zu lschen, die einen Artikel enthlt, der noch gebraucht wird. Sie knnen auerdem
einen Artikel nur lschen, wenn er in keiner Rechnung mehr enthalten ist.
Erfahrene Datenbankexperten wissen sicherlich, wie in relationalen Datenbanksystemen referentielle Integritt sichergestellt werden kann: Mit Primrschlssel, Fremdschlssel, References und
einer Constraint-Klausel. In db4o mssen Sie dahingehend umdenken: Sie mssen referentielle
Integritt zum Groteil in der Anwendung selbst festlegen.
So knnen Sie im Projekt selbst folgendes sicherstellen: Es sollen nur Artikel in eine Rechnung
eingegeben werden, die bereits existieren. Wohingegen Sie beim Lschen von Rechnungen und
Artikel zustzlich genaue Kenntnisse der Lschvorgnge in db4o bentigen. In db4o knnen Sie
von Fall zu Fall und von Ebene zu Ebene separat festlegen, welche Daten Sie lschen und welche
nicht.

4.3 Theoretische Datenbankgrundlagen und db4o


Im nchsten Kapitel Beziehungen in einem objektorientierten Datenbankentwurf  werde ich anhand unseres Content-Management-Systems darlegen, wie diese theoretischen Datenbankgrundlagen in db4o umgesetzt worden sind. Datenredundanz lsst sich verhindern, indem Sie die verschiedenen Beziehungen des Entity-Relationship-Modells umsetzen und einhalten.
Wohingegen Sie bei der referentiellen Integritt umdenken mssen. Sie mssen manche Probleme
in dem Projekt selbst lsen. So ist z.B. eine der Mglichkeiten Daten nicht zu lschen, die noch
gebraucht werden, eine if-Abfrage. Dies werden wir ausfhrlich am Beispiel der Formatierungen
sehen. Wir lernen, wie wir eine bestimmte Formatierung nur lschen, wenn keine Texte mehr
vorhanden sind, die zu dieser Formatierung gehren.

32

5 Beziehungen in einem objektorientierten


Datenbankentwurf
Wie werden Probleme mit der Datenredundanz in db4o gelst? Schritt fr Schritt werden wir
uns das objektorientierte Konzept anhand des Entitiy-Relationship-Modells erarbeiten. In diesem
Kapitel wollen wir uns mit den verschiedenen Beziehungen beschftigen, die es in einer objektorientierten Datenbank gibt. Es sind die Folgenden: die 1:1-Beziehung, die 1:n-Beziehung, die
m:n-Beziehung und die Vererbungsbeziehungen.

5.1 Die 1:1-Beziehung: die has-a-Beziehung


Als Nchstes wollen wir uns die 1:1-Beziehung zwischen 2 Klassen ansehen, nmlich zwischen der
Klasse FormatierungEinfach und der Klasse TextEinfach. Fr einen Text ist es unumgnglich
Schrift und Schriftgre festzulegen. So ist eine CSS-Formatierung ein wichtiger Teil unserer
Klasse Text. Und wir geben der Klasse TextEinfach zwei Bestandteile: die Variable name und
das Objekt FormatierungEinfach. Die Beziehung zwischen Text und Formatierung nennt man
has-a-Beziehung, da die Klasse TextEinfach ein Objekt der Klasse FormatierungEinfach hat .
In einem Objekt der Klasse TextEinfach wird der entsprechende Unique Object Identier oder
OID des Objektes der Klasse FormatierungEinfach gespeichert.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package Datenbankentwurf;
public class TextEinfach {
private String name;
private FormatierungEinfach formatierungEinfach;
public TextEinfach(){
this.name = name;
this.formatierungEinfach = formatierungEinfach;
}
public TextEinfach(String name) {
this.name = name;
this.formatierungEinfach = formatierungEinfach;
}
public TextEinfach(String name, FormatierungEinfach formatierungEinfach) {
this.name = name;
this.formatierungEinfach = formatierungEinfach;
}
public String getName() {

33

5 Beziehungen in einem objektorientierten Datenbankentwurf

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

return name;

public void setName(String name) {


this.name = name;
}
public FormatierungEinfach getFormatierungEinfach() {
return formatierungEinfach;
}

public void setFormatierungEinfach(FormatierungEinfach formatierungEinfach) {


this.formatierungEinfach = formatierungEinfach;
}

Listing 5.1: TextEinfach.java

5.1.1 Speichern, Auslesen und Lschen von Objekten der Klasse TextEinfach
Unsere Datenbank besteht bis dato aus drei Klassen: der Klasse TextEinfach, FormatierungEinfach und Bild. Der Datenbankentwurf nimmt an Komplexitt und Umfang zu. Ebenso wie unsere
Abfragen. Und so wird unsere nchste Frage sein: Welche Besonderheiten sind bei den Datenbankabfragen und einer has-a-Beziehung zu beachten? Und wie knnen Probleme gelst werden?

Speichern
Lassen Sie uns mit dem Speichern unseres TextEinfach-Objektes beginnen. Folgendes ist unser
Ziel: Wir wollen nicht, dass beim Speichern eines neuen TextEinfach-Objektes, jedes Mal ein neues
FormatierungEinfach-Objekt erzeugt wird. Wie knnen wir dies in unserer objektorientierten
Datenbank db4o erreichen? Sie drfen die CSS-Formatierung eines Textes erst zuweisen, wenn
die Datenbank oen ist, da Sie ja das bereits existierende FormatierungEinfach-Objekt zuweisen
wollen.
Nach nen der Datenbank lesen Sie als Erstes das entsprechende bereits existierende Objekt aus und erst dann weisen Sie mit der Methode setFormatierungEinfach() dem Text ein
FormatierungEinfach-Objekt zu. Im Anschlu daran speichern Sie das TextEinfach-Objekt und
schlieen die Datenbank wieder.

1
2
3
4
5
6
7
8
9
10

34

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
Datenbankentwurf.TextEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

public class TextSpeichern {

5.1 Die 1:1-Beziehung: die has-a-Beziehung

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

public void speichern(TextEinfach t, FormatierungEinfach f){


ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
/*Sie mssen das bereits existierende Objekt auslesen und
dieses dann auch dem TextEinfach-Objekt zuweisen.*/
ObjectSet<FormatierungEinfach> result = db.get(f);
FormatierungEinfach fo = result.next();
t.setFormatierungEinfach(fo);
db.set(t);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

}
Listing 5.2: TextSpeichern.java

Auslesen
Wie werden die TextEinfach-Objekte wieder ausgelesen? Mssen wir auch auf Besonderheiten
achten, wie wir es beim Speichern der Objekte getan haben? Nein. Sie knnen analog vorgehen, wie beim Auslesen von FormatierungEinfach-Objekten: mit der Methode get() und einem
Beispielobjekt der Klasse TextEinfach.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.TextEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class TextAuslesen {


public ArrayList<TextEinfach> auslesen(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");

35

5 Beziehungen in einem objektorientierten Datenbankentwurf

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

ArrayList<TextEinfach> f = new ArrayList<TextEinfach>();


try {
TextEinfach t = new TextEinfach(null);
ObjectSet<TextEinfach> result = db.get(t);
while (result.hasNext()){
t = result.next();
f.add(t);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return f;

}
}

Listing 5.3: TextAuslesen.java


Dies war doch einfach? Oder nicht? Was mssen Sie tun, um ein bestimmtes TextEinfach-Objekt
auszulesen? Dies geschieht auch wie weiter oben bei den CSS-Fromatierungen: Sie mssen der
Methode auslesenEinzeln() das entsprechende Beispielobjekt bergeben:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

36

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.TextEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class TextAuslesenEinzeln {


public TextEinfach auslesenEinzeln(TextEinfach t){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<TextEinfach> result = db.get(t);

5.1 Die 1:1-Beziehung: die has-a-Beziehung

21
22
23
24
25
26
27
28
29
30
31
32
33

while (result.hasNext()){
t = result.next();
}

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return t;

}
Listing 5.4: TextAuslesenEinzeln.java

Lschen
Welche Probleme knnen beim Lschen auftauchen? Wie knnen Sie in db4o ungewolltes Lschen
unterbinden? Dazu sollten wir verstehen, was genau passiert, wenn wir ein Textobjekt lschen().
Wird das FormatierungEinfach-Objekt mitgelscht?
Wir erstellen eine Klasse TextLoeschen.java mit einer Methode loeschen, die unsere TextEinfachObjekte lschen soll:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

package Kap05;
import
import
import
import
import

Datenbankentwurf.TextEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

public class TextLoeschen {


public void loeschen(TextEinfach t){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<TextEinfach> result = db.get(t);
TextEinfach te = result.next();
db.delete(te);
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{

37

5 Beziehungen in einem objektorientierten Datenbankentwurf

25
26
27
28

db.close();

Listing 5.5: TextLoeschen.java


Um TextEinfach-Objekte lschen zu knnen, mssen wir als Erstes TextEinfach-Objekte anlegen.
Wir erstellen sowohl zwei FormtierungEinfach-Objekte als auch zwei TextEinfach-Objekte. Zuerst
legen wir zwei FormatierungEinfach-Objekte an, da sie die Voraussetzung fr das Erstellen von
TextEinfach-Objekten sind.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package Kap05;
import Kap03.FormatierungDatenSpeichern;
import Datenbankentwurf.FormatierungEinfach;
public class FormatierungInDatenbank {
public static void main(String[] args){
FormatierungDatenSpeichern fd = new FormatierungDatenSpeichern();
FormatierungEinfach f = new FormatierungEinfach("font1");
FormatierungEinfach fo = new FormatierungEinfach("font2");

fd.speichern(f);
fd.speichern(fo);

Listing 5.6: FormatierungInDatenbank.java


Auf Basis der CSS-Formatierungen font1 und font2 erstellen wir in der Klasse TextInDatenbank.java zwei Texte und speichern diese ebenfalls in der Datenbank:

1
2
3
4
5
6
7
8
9
10
11
12

38

package Kap05;
import Datenbankentwurf.FormatierungEinfach;
import Datenbankentwurf.TextEinfach;
public class TextInDatenbank {
public static void main(String[] args){
TextEinfach t = new TextEinfach("Ich bin ein Text!");
FormatierungEinfach f = new FormatierungEinfach("font1");

5.1 Die 1:1-Beziehung: die has-a-Beziehung

13
14
15
16
17
18
19
20
21

TextEinfach te = new TextEinfach("Ich bin noch ein Text!");


FormatierungEinfach fe = new FormatierungEinfach("font2");
TextSpeichern ts = new TextSpeichern();
ts.speichern(t, f);
ts.speichern(te, fe);
}

Listing 5.7: TextInDatenbank.java


Lassen Sie uns nun sowohl die Formatierungen als auch die Texte mit den zugehrigen Formatierungen auslesen, um zu berprfen, ob unsere Objekte in der Datenbank angelegt worden
sind. Und wie unten stehende Ausgabe auf der Konsole zeigt, wurden alle FormatierungEinfachObjekte und alle TextEinfachObjekte so gespeichert, wie wir es erwartet haben.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

package Kap05;
import
import
import
import

Kap03.FormatierungDatenAuslesen;
Datenbankentwurf.FormatierungEinfach;
Datenbankentwurf.TextEinfach;
java.util.ArrayList;

public class TextAusDatenbank {


public static void main(String[] args){
FormatierungDatenAuslesen fd = new FormatierungDatenAuslesen();
ArrayList<FormatierungEinfach> al = fd.auslesen();
for(FormatierungEinfach fo: al){
System.out.println("Auslesen Formatierung: "+fo.getName());
}
TextAuslesen ta = new TextAuslesen();
ArrayList<TextEinfach> at = ta.auslesen();

for(TextEinfach t: at){
System.out.println("Auslesen Text: "+ t.getName());
System.out.println("Auslesen Text-Formatierung: "
+ t.getFormatierungEinfach().getName());
}

Listing 5.8: TextAusDatenbank.java

39

5 Beziehungen in einem objektorientierten Datenbankentwurf

Ausgabe:
Auslesen Formatierung: font2
Auslesen Formatierung: font1
Auslesen Text: Ich bin ein Text!
Auslesen Text-Formatierung: font1
Auslesen Text: Ich bin noch ein Text!
Auslesen Text-Formatierung: font2
Wir knnen auch ein bestimmtes TextEinfach-Objekt und ein dazugehriges FormatierungEinfachObjekt mit der Methode auslesenEinzeln() ausgeben:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package Kap05;
import Datenbankentwurf.FormatierungEinfach;
import Datenbankentwurf.TextEinfach;
public class TextAusDatenbankEinzeln {
public static void main(String[] args){
TextAuslesenEinzeln tae = new TextAuslesenEinzeln();
FormatierungEinfach fe = new FormatierungEinfach("font1");
TextEinfach te = new TextEinfach("Ich bin ein Text!", fe);
TextEinfach tex = tae.auslesenEinzeln(te);
System.out.println("Text: "+tex.getName());
System.out.println("Textformatierung: "
+ tex.getFormatierungEinfach().getName());
}
}
Listing 5.9: TextAusDatenbankEinzeln.java

Ausgabe:
Text: Ich bin ein Text!
Textformatierung: font1
Im nchsten Schritt lschen wir in der Klasse TextDatenbankLoeschen.java das Objekt TextEinfach mit dem Inhalt Ich bin ein Text! wieder.

1
2
3

40

package Kap05;
import Datenbankentwurf.FormatierungEinfach;

5.1 Die 1:1-Beziehung: die has-a-Beziehung

4
5
6
7
8
9
10
11
12
13
14
15
16
17

import Datenbankentwurf.TextEinfach;
public class TextDatenbankLoeschen {
public static void main(String[] args){
FormatierungEinfach f = new FormatierungEinfach("font1");
TextEinfach t = new TextEinfach("Ich bin ein Text!", f);
TextLoeschen tl = new TextLoeschen();
tl.loeschen(t);
}

Listing 5.10: TextDatenbankLoeschen.java


Lesen wir nach diesem Lschvorgang die Texte und die Formatierungen wieder mit der Klasse
TextAusDatenbank aus der Datenbank aus, erhalten wir eine Ausgabe, wie wir sie erhot hatten:
Auslesen Formatierung: font2
Auslesen Formatierung: font1
Auslesen Text: Ich bin noch ein Text!
Auslesen Text-Formatierung: font2
Fazit: Das FormatierungEinfach-Objekt wurde nicht gelscht, es wurde nur das TextEinfachObjekt gelscht. Es wird also nur der Wert der Variablen eines Objektes gelscht und nicht die
darin enthaltenen Objekte. bertragen wir das Ergebnis auf unser Rechnungsbeispiel, wrde nur
beim Lschen einer Rechnung nur die Rechnung gelscht und nicht die darin enthaltenen Artikeloder Kundenstammdaten.

Lschen mit cascadeOnDelete()


Wollen Sie aber nicht nur das Objekt TextEinfach lschen, sondern auch das darin enthaltene
FormatierungEinfach-Objekt, bentigen Sie die Methode cascadeOnDelete(). Die gesamte Befehlszeile lautet:
Db4o . c o n f i g u r e ( ) . o b j e c t C l a s s ( T e x t E i n f a c h . c l a s s ) . c a s c a d e O n D e l e t e ( t r u e ) ;
Sie mu vor dem nen der Datenbank eingefgt werden.

1
2
3
4
5
6
7
8

package Kap05;
import
import
import
import
import

Datenbankentwurf.TextEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

41

5 Beziehungen in einem objektorientierten Datenbankentwurf

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

public class TextLoeschenCascade {


public void loeschen(TextEinfach t){
Db4o.configure().objectClass(TextEinfach.class).cascadeOnDelete(true);
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<TextEinfach> result = db.get(t);
TextEinfach te = result.next();
db.delete(te);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.11: TextLoeschenCascade.java


Testen wir oben stehendes Listing: Sie entfernen oben stehende Datenbank, indem Sie sie mit
der Entf-Taste lschen, und erstellen erneut die Objekte mithilfe der Klasse FormatierungInDatenbank.java und TextInDatenbank.java. Anschlieend lschen wir das TextEinfach-Objekt mit
der Methode loeschen() aus der Klasse TextLoeschenCascade.java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

package Kap05;
import Datenbankentwurf.FormatierungEinfach;
import Datenbankentwurf.TextEinfach;
public class TextDatenbankLoeschenCascade {
public static void main(String[] args){
FormatierungEinfach f = new FormatierungEinfach("font1");
TextEinfach t = new TextEinfach("Ich bin ein Text!", f);
TextLoeschenCascade tl = new TextLoeschenCascade();
tl.loeschen(t);
}

Listing 5.12: TextDatenbankLoeschenCascade.java

42

5.1 Die 1:1-Beziehung: die has-a-Beziehung

Wir erhalten mit TextAusDatenbank.java folgende Ausgabe:


Auslesen Formatierung: font2
Auslesen Text: Ich bin noch ein Text!
Auslesen Text-Formatierung: font2
Wir haben also beide gelscht, sowohl das TextEinfach- als auch das FormatierungEinfachObjekt. Also Vorsicht: Diese Art zu lschen bitte nur verwenden, wenn Sie wirklich wollen,
dass auch das FormatierungEinfach-Objekt gelscht wird und nicht nur das TextEinfach-Objekt.
Datenbankpros kennen das Konzept, dass das ungewollte Lschen von Daten verhindern soll, als
referentielle Integritt . Die Methode cascadeOnDelete() erfllt diese Bedingung nicht, sondern
hat das Gegenteil zur Folge.

ndern
Welche Besonderheiten gilt es zu beachten, wenn Sie ein TextEinfach-Objekt und gleichzeitig das darin enthaltene FormatierungsEinfach-Objekt ndern wollen? Sie mssen sowohl das
TextEinfach-Objekt als auch das FormatierungEinfach-Objekt aus der Datenbank auslesen, um
genau das Objekt auszulesen, das verndert werden soll. Unten stehend nden Sie die entsprechende Klasse TextAendern.java mit der Methode aendern().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
Datenbankentwurf.TextEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

public class TextAendern {


public void aendern(TextEinfach t, TextEinfach te,
FormatierungEinfach f){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
/*Das zu verndernde TextEinfach-Objekt muss aus der
Datenbank ausgelesen werden.*/
ObjectSet<TextEinfach> result = db.get(t);
TextEinfach text = result.next();
/*Der Inhalt des Textes wird verndert:*/
text.setName(te.getName());
/*Sie mssen das FormatierungEinfach-Objekt direkt aus der Datenbank

43

5 Beziehungen in einem objektorientierten Datenbankentwurf

auslesen, nur so ist gewhrleistet, dass sie immer wieder auf das
gleiche Objekt zugreifen und nicht ein Neues erstellen.*/
ObjectSet<FormatierungEinfach> resultFormatierung = db.get(f);

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

FormatierungEinfach fo = resultFormatierung.next();
/*Das Format des Textes wird verndert:*/
text.setFormatierungEinfach(fo);
/*Das TextEinfach-Objekt wird wieder gespeichert:*/
db.set(text);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.13: TextAendern.java


Wir beginnen wieder damit die Datenbank zu lschen und erstellen erneut unsere Objekte mithilfe
der Klassen FormatierungInDatenbank.java und TextInDatenbank.java. In der Klasse TextDatenbankAendern.java wollen wir unser TextEinfach-Objekt mit Namen Ich bin ein Text! ndern:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

package Kap05;
import Datenbankentwurf.FormatierungEinfach;
import Datenbankentwurf.TextEinfach;
public class TextDatenbankAendern {
public static void main(String[] args){
FormatierungEinfach f = new FormatierungEinfach("font1");
TextEinfach t = new TextEinfach("Ich bin ein Text!", f);
FormatierungEinfach fo = new FormatierungEinfach("font2");
TextEinfach te = new TextEinfach("Ich bin ein neuer Text!");

TextAendern tae = new TextAendern();


tae.aendern(t, te, fo);

Listing 5.14: TextDatenbankAendern.java

44

5.1 Die 1:1-Beziehung: die has-a-Beziehung

Geben wir unsere Daten mit TextAusDatenbank.java wieder aus, knnen wir sehen, dass uns das
ndern eines TextEinfach-Objektes gelungen ist und immer noch genauso viele Formatierungsobjekte vorhanden sind wie vorher.

Ausgabe:
Auslesen Formatierung: font2
Auslesen Formatierung: font1
Auslesen Text: Ich bin ein neuer Text!
Auslesen Text-Formatierung: font2
Auslesen Text: Ich bin noch ein Text!
Auslesen Text-Formatierung: font2

Exkurs
Fr alle, die  so wie ich  Bcher querlesen, fragen sich vielleicht, warum ich nicht die Methode
cascadeOnUpdate() verwendet habe? Analog zur Vorgehensweise beim Hinzufgen von Elementen zu einer ArrayList, die sich in einem Objekt bendet? Ganz einfach: Dies hat nicht den
gewnschten Eekt. Sie knnen damit

nicht das FormatierungEinfach-Objekt im TextEinfach-

Objekt verndern, da dies einen unerwnschten Nebeneekt hat. Sollte Sie diese Ausfhrungen
irritieren, berspringen Sie sie einfach und kommen vielleicht spter wieder darauf zurck.
Erstellen wir eine entsprechende Methode aendern() und probieren es aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.FormatierungEinfach;
Datenbankentwurf.TextEinfach;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

public class TextAendernCascade {


public void aendern(TextEinfach t, TextEinfach te,
FormatierungEinfach f){
Db4o.configure().objectClass(TextEinfach.class).
cascadeOnUpdate(true);
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<TextEinfach> result = db.get(t);
TextEinfach text = result.next();

45

5 Beziehungen in einem objektorientierten Datenbankentwurf

text.setName(te.getName());
text.setFormatierungEinfach(f);

26
27
28
29
30
31
32
33
34
35
36
37

db.set(text);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.15: TextAendernCascade.java


Wir ndern wieder das TextEinfach-Objekt mit Inhalt Ich bin ein Text! und der Formatierung
font1 in Ich bin ein neuer Text! mit der Formatierung font.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package Kap05;
import Datenbankentwurf.FormatierungEinfach;
import Datenbankentwurf.TextEinfach;
public class TextDatenbankAendernCascade {
public static void main(String[] args){
FormatierungEinfach f = new FormatierungEinfach("font1");
TextEinfach t = new TextEinfach("Ich bin ein Text!", f);
FormatierungEinfach fo = new FormatierungEinfach("font2");
TextEinfach te
= new TextEinfach("Ich bin ein neuer Text!");
TextAendernCascade tae = new TextAendernCascade();
tae.aendern(t, te, fo);
}

Listing 5.16: TextDatenbankAendernCascade.java

Ausgabe:
Auslesen Formatierung: font2
Auslesen Formatierung: font1
Auslesen Formatierung: font2
Auslesen Text: Ich bin ein neuer Text!

46

5.2 Vererbungsbeziehungen

Auslesen Text-Formatierung: font2


Auslesen Text: Ich bin noch ein Text!
Auslesen Text-Formatierung: font2
Also Vorsicht: Er ndert zwar die Daten wie gewnscht, aber er erstellt auch zustzlich ein neues
FormatierungEinfach-Objekt.

5.2 Vererbungsbeziehungen
Eine der wichtigsten Bausteine einer objektorientierten Programmiersprache sind Vererbungsbeziehungen. Wie knnen diese in der Datenbank db4o abgebildet werden? Welche Auswirkungen
haben Interfaces, Abstrakte Klassen und Super- und Subklassen auf Abfragen?

5.2.1 Super- und Subklassen


Was verbindet eine Superklasse mit einer Subklasse? Die Subklasse erbt von der Superklasse. Es
verhlt sich hnlich wie bei Vater und Kind: Das Kind erbt vom Vater. Es liegt eine sogenannte
is-a-Beziehung vor. Ein Kind erbt vom Vater und ist somit vom Typ her ein Vater.
Wo kommt dieses Prinzip in unserem Datenbankentwurf zum Einsatz? In unserem ContentManagement-System gibt es zwei Elemente, die noch in unserer Datenbank abgebildet werden
mssen: Hyperlinks und PDFs. Fr diese zwei Klassen erstellen wir eine Vaterklasse Verlinkung,
die aus einer Variablen name besteht:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package Datenbankentwurf;
public class Verlinkung {
private String name;
public Verlinkung() {
}
public Verlinkung(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Listing 5.17: Verlinkung.java

47

5 Beziehungen in einem objektorientierten Datenbankentwurf

Unsere erste Kindklasse ist die Klasse Link, die durch eine extends-Beziehung zur Subklasse der
Klasse Verlinkung wird.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

package Datenbankentwurf;
public class Link extends Verlinkung{
public Link(){
}
public Link(String name) {
/*wir rufen mit dem Konstruktoraufruf super(name)
den Konstruktor mit Parameter der Superklasse auf*/
super(name);
}
}
Listing 5.18: Link.java

Die zweite Kindklasse unserer Klasse Verlinkung ist unsere Klasse PDF, die zustzlich eine
Variable Pfad beinhaltet. Der Pfad enthlt das Verzeichnis, in dem sich das PDF auf dem Server
bendet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

48

package Datenbankentwurf;
public class PDF extends Verlinkung{
private String pfad;
public PDF() {
}
public PDF(String name) {
/*wir rufen mit dem Konstruktoraufruf super(name)
den Konstruktor mit Parameter der Superklasse auf*/
super(name);
this.pfad = pfad;
}
public PDF(String name, String pfad) {
/*wir rufen mit dem Konstruktoraufruf super(name)

5.2 Vererbungsbeziehungen

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

den Konstruktor mit Parameter der Superklasse auf*/


super(name);
this.pfad = pfad;
}
public String getPfad() {
return pfad;
}
public void setPfad(String pfad) {
this.pfad = pfad;
}
}
Listing 5.19: PDF.java

Die Klasse Link und PDF sind durch Verwandschaftsbeziehungen miteinander verbunden: Sie
sind beide Subklassen der Klasse Verlinkung. Somit steht in jedem Konstruktor der Klasse Link
und der Klasse PDF implizit ein Aufruf super(), der den Standardkonstruktor der Superklasse
aufruft, den ersetzen wir durch ein Aufruf super(name). Der Konstruktoraufruf super(name) ruft
den Konstruktor mit Parameter name der Vaterklasse auf. Somit stehen Ihnen in den Subklassen
alle Methoden der Superklasse zur Verfgung.

Speichern und Auslesen von Objekten der Klasse Verlinkung, Link und PDF
Wie wirkt sich die Vererbungsbeziehung zwischen der Klasse Verlinkung, Link und PDF auf das
Speichern und Auslesen aus? Was gilt es Besonderes zu beachten?

Speichern
Lassen Sie uns zwei Klassen erstellen, die Methoden zum Speichern unserer Objekte enthalten.
Die Methode set(), die ein Objekt in der Datenbank speichert, ist uns bereits aus den vorangegangenen Abschnitten bekannt. Die Klasse LinkSpeichern.java und ihre Methode speichern()
speichert die Objekte der Klasse Link:

1
2
3
4
5
6
7
8
9
10
11
12

package Kap05;
import
import
import
import

Datenbankentwurf.Link;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ext.DatabaseFileLockedException;

public class LinkSpeichern {


public void speichern(Link l){
ObjectContainer db = Db4o.openFile

49

5 Beziehungen in einem objektorientierten Datenbankentwurf

("C:/Datenbank/DasErsteProjekt/datenbank.yap");

13
14
15
16
17
18
19
20
21
22
23
24
25

try {
db.set(l);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.20: LinkSpeichern.java


Und die Klasse PDFSpeichern.java liest PDF-Objekte mithilfe der Methode speichern() in die
Datenbank ein:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

package Kap05;
import
import
import
import

Datenbankentwurf.PDF;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ext.DatabaseFileLockedException;

public class PDFSpeichern {


public void speichern(PDF p){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
db.set(p);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.21: PDFSpeichern.java

50

5.2 Vererbungsbeziehungen

Wir lschen die bereits existierende Datenbank wieder und erstellen mit unten stehender Klasse
LinkPDFInDatenbank.java eine neue, in der wir sowohl zwei Links als auch zwei PDFs speichern.
Wir knnen sowohl Links als auch PDFs Namen vergeben, da sie die entsprechenden Methoden
aus der Vaterklasse Verlinkung geerbt haben.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

package Kap05;
import Datenbankentwurf.Link;
import Datenbankentwurf.PDF;
import Kap05.LinkSpeichern;
public class LinkPDFInDatenbank {
public static void main(String[] args){
//Es werden zwei Links gespeichert
LinkSpeichern ls = new LinkSpeichern();
Link l = new Link("eins");
Link li = new Link("zwei");
ls.speichern(l);
ls.speichern(li);
//Es werden zwei PDFs gespeichert
PDFSpeichern ps = new PDFSpeichern();
PDF p = new PDF("links", "PDF/links.pdf");
PDF pdf = new PDF("rechts", "PDF/rechts.pdf");
ps.speichern(p);
ps.speichern(pdf);
}

Listing 5.22: LinkPDFInDatenbank.java


Soweit nichts Neues: Verwandtschaftsbeziehungen haben keinen Einuss beim Speichern von
Objekten.

Auslesen
Wie werden unsere Objekte der Klasse Link und der Klasse PDF wieder ausgelesen? Und welche
Bedeutung spielt hierbei, dass beide Klassen Subklassen der Klasse Verlinkung sind? Was lsst
sich vermuten? Da es sich um eine is-a-Beziehung handelt und sowohl Links als auch PDFs eine
is-a-Beziehung zu der Klasse Verlinkung haben, mssten eigentlich alle Links und PDF ausgelesen
werden, wenn wir Objekte der Klasse Verlinkung auslesen. Dies werden wir berprfen. Folgende
Klasse mit der Methode auslesen(), liest alle Objekte der Klasse Verlinkung aus:

51

5 Beziehungen in einem objektorientierten Datenbankentwurf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.Verlinkung;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class VerlinkungAuslesen {


public ArrayList<Verlinkung> auslesen(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Verlinkung> f = new ArrayList<Verlinkung>();
try {
Verlinkung v = new Verlinkung(null);
ObjectSet<Verlinkung> result = db.get(v);
while (result.hasNext()){
v = result.next();
f.add(v);
}

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return f;

}
Listing 5.23: VerlinkungAuslesen.java

Und tatschlich fhren wir die Methode auslesen() durch, werden sowohl alle Links als auch alle
PDFs auf der Konsole ausgegeben:

1
2
3
4
5
6

52

package Kap05;
import Datenbankentwurf.Verlinkung;
import java.util.ArrayList;
public class VerlinkungAusDatenbank {

5.2 Vererbungsbeziehungen

7
8
9
10
11
12
13
14
15
16
17
18
19

public static void main(String[] args){


VerlinkungAuslesen va = new VerlinkungAuslesen();
ArrayList<Verlinkung> al = va.auslesen();
for(Verlinkung v : al){
System.out.println("Verlinkungen Name: "+v.getName() );
}
}

Listing 5.24: VerlinkungAusDatenbank.java

Ausgabe:
Verlinkungen: eins
Verlinkungen: zwei
Verlinkungen: rechts
Verlinkungen: links
Machen wir nun die Probe aufs Exempel: Werden nur alle Links ausgelesen, wenn wir eine
Methode auslesen() fr die Klasse Link erstellen?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.Link;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class LinkAuslesen {


public ArrayList<Link> auslesen(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Link> f = new ArrayList<Link>();
try {
Link l = new Link(null);
ObjectSet<Link> result = db.get(l);

53

5 Beziehungen in einem objektorientierten Datenbankentwurf

while (result.hasNext()){
l = result.next();
f.add(l);
}

24
25
26
27
28
29
30
31
32
33
34
35
36
37

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return f;

}
Listing 5.25: LinkAuslesen.java
Wir lesen alle Linkobjekte und ihre Namen aus. Sie knnen keine Pfade auslesen, da die Klasse
Link keine Variable pfad und die entsprechenden Getter- und Setter-Methoden enthlt. Diese
gibt es nur in der Klasse PDF.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

package Kap05;
import Datenbankentwurf.Link;
import java.util.ArrayList;
public class LinkAusDatenbank {
public static void main(String[] args){
LinkAuslesen la = new LinkAuslesen();
ArrayList<Link> al = la.auslesen();
for(Link li : al){
System.out.println("Link Name: "+li.getName() );
}
}

Listing 5.26: LinkAusDatenbank.java

Ausgabe:
Link Name: eins
Link Name: zwei

54

5.3 1:n-Beziehung

Es werden nur die Objekte der Klasse Link ausgelesen und nicht die Objekte der Klasse PDF.
Fazit: Unser obige Vermutung kann also mit Ja beantwortet werden. Es werden alle Links und
PDFs ausgelesen, wenn alle Verlinkungen ausgelesen werden. Und nur alle Links, wenn Links
ausgelesen werden und nur alle PDFs, wenn PDFs ausgelesen werden. Also: Denken Sie immer
an die Vererbungsbeziehungen zwischen den einzelnen Klassen der Datenbank, wenn Sie Daten
aus der Datenbank auslesen wollen.

5.2.2 Interfaces und Abstrakte Klassen


Interfaces, bersetzt Schnittstellen, stellen eine Art Vorschriftenkatalog dar, der festlegt welche
Methoden in einer Klasse eingefgt werden mssen, die das Interface implementieren. Da das
Interface nur sicherstellen soll, dass sich Methoden in der Klasse benden, enthlt ein Interface
nur leere Methoden, die in der Klasse selbst mit Inhalt gefllt werden mssen. Eine Klasse besitzt
eine implements-Beziehung zu einem Interface:
public

class

Formatierung

implements

I n t e r f a c e F o r m a t i e r u n g {}

Abstrakte Klassen haben hnliche Aufgaben wie Interfaces. Sie besitzen auch Implementierungsvorschriften, aber im Gegensatz zu einem Interface knnen Sie auch Methoden enthalten, die
nicht leer sind.
Da Sie weder Interfaces noch Abstrakte Klassen instanziieren knnen, knnen Sie auch nicht mit
Query-by-Example ein Beispielobjekt aus einem Interface oder einer Abstrakten Klasse erstellen.
Wie knnen Sie aber Objekte auslesen, die ein bestimmtes Interface implementieren? Und konkret: Wie lesen wir Objekte aus, die das Interface InterfaceFormatierung implementieren? db4o
stellt Ihnen deswegen eine zustzliche Funktion zur Verfgung:
InterfaceFormatierung . c l a s s
Diese Befehlszeile mssen Sie anstelle eines Beispielobjektes der Methode get() bergeben:
Object . Set

result

= db . g e t ( I n t e r f a c e F o r m a t i e r u n g . c l a s s ) ;

Das gleiche gilt fr alle Objekte, die eine extends-Beziehung zu einer abstrakten Klasse haben.

5.3 1:n-Beziehung
Kehren wir zu unseren Formatierungen und Texten zurck. Wir hatten zwei Klassen deniert:
die Klasse FormatierungEinfach.java und die Klasse TextEinfach.java. Diese zwei Klassen hatten
eine 1:1-Beziehung zueinander. Was machen wir aber, wenn wir viele verschiedene Texte haben,
die jeweils

einer CSS-Formatierung zugewiesen werden? Dies lsst sich nur schlecht durch unsere

bisherigen Klassen abbilden.


Also stellt sich die Frage: Wie knnen wir eine 1:n-Beziehung darstellen? Durch eine ArrayList.
Eine ArrayList kann mehrere Objekte der Klasse Text aufnehmen. Wir haben also jetzt unsere
abgenderte Klasse Text, die kein Objekt Formatierung mehr enthlt:

1
2
3
4
5

package Datenbankentwurf;
import java.util.List;
public class Text {

55

5 Beziehungen in einem objektorientierten Datenbankentwurf

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

private String name;


public Text(){}
public Text(String name) {
this.name = name;
}
public String getName() {
return name;
}

public void setName(String name) {


this.name = name;
}

Listing 5.27: Text.java


Stattdessen haben wir eine Klasse Formatierung, die zustzlich zu der Variablen name eine
ArrayList als Bestandteil hat, die wiederum eine Vielzahl von Textobjekten aufnehmen kann.
Viele Texte knnen also einer Formatierung zugewiesen werden. Jetzt haben wir also keine 1:1Beziehung mehr, sondern eine 1:n Beziehung.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

56

package Datenbankentwurf;
import java.util.ArrayList;
public class Formatierung {
private String name;
private ArrayList<Text> text;
public Formatierung(){}
public Formatierung(String name){
this.name = name;

/*an dieser Stelle muss ein neue ArrayList erstellt


werden, nur so knnen Sie spter der ArrayList
Elemente hinzufgen*/
this.text = new ArrayList<Text>();

public Formatierung(String name, ArrayList<Text> text) {


this.name = name;
this.text = text;
}

5.3 1:n-Beziehung

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

public String getName() {


return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<Text> getText() {
return text;
}
public void setText(ArrayList<Text> text) {
this.text = text;
}
}

Listing 5.28: Formatierung.java

Im nchsten Abschnitt werden wir anhand von Beispielen nher betrachten, wie wir mit diesen
Formatierungsobjekten Abfragen gestalten, die uns zuerst ermglichen sollen, Formatierungen
anzulegen, zu lschen und zu ndern. Erst danach werden wir zu den Formatierungen, Texte
hinzufgen. Die Eingabemaske in unserem Content-Management-System soll wie folgt aussehen:

Abbildung 5.1: Eingabemaske fr unsere Formatierungen

Im Kapitel Unser Content-Management-System werden wir sehen, wie wir diese Eingabemaske
und die dazugehrigen Lschen- und ndern-Formulare mit JSPs und Servlets umsetzen knnen.

57

5 Beziehungen in einem objektorientierten Datenbankentwurf

5.3.1 db4o Collections und die ArrayList


Wir haben die ArrayList, eine Java-Standardklasse aus dem Collections-Framework verwendet,
um eine 1:n-Beziehung abbilden zu knnen. Die ArrayList stellt eine der drei schnellsten Mglichkeiten in db4o dar, dies zu tun. Wir werden die ArrayList auch weiterhin verwenden. Besonders
hingewiesen sei noch auf zwei Methoden der Klasse ArrayList: Erstens auf die Methode add(),
die es ermglicht Element der ArrayList hinzuzufgen und zweitens auf die Methode remove(),
die Elemente aus der ArrayList wieder entfernt.
db4o empehlt zustzlich die LinkedList und die HashMap der db4o Collections, die sich im
Package com.db4o.types benden.

Abbildung 5.2: db4o Collections

5.3.2 Speichern, Auslesen, ndern und Lschen von Formatierungsobjekten


Im ersten Schritt erstellen wir Klassen, die Abfragen bezglich unseres Formatierungsobjektes
enthalten. Texte werden wir spter hinzufgen und wieder lschen.

Speichern
Erstens speichern wir wieder, wie gehabt, mit der set()-Methode unser Objekt der Klasse Formatierung:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

58

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class FormatierungSpeichern {


public void speichern(Formatierung f){
ObjectContainer db = Db4o.openFile

5.3 1:n-Beziehung

15
16
17
18
19
20
21
22
23
24
25
26
27

("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
db.set(f);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.29: FormatierungSpeichern.java

Auslesen
Zweitens wird das Formatierungsobjekt in der Klasse FormatierungAuslesen.java wieder mit der
Methode get() und einem Beispielobjekt aus der Datenbank ausgelesen. Dem Beispielobjekt der
Klasse Formatierung mssen Sie zwei Standardwerte bergeben, da sie zwei Bestandteile hat:
Formatierung

p = new

Formatierung ( n u l l ,

null );

Die gesamte Methode auslesen(), die eine ArrayList<Formatierung> zurckgibt, sieht dann wie
folgt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class FormatierungAuslesen {


public ArrayList<Formatierung> auslesen(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Formatierung> f = new ArrayList<Formatierung>();
try {
Formatierung p = new Formatierung(null, null);
ObjectSet<Formatierung> result = db.get(p);

59

5 Beziehungen in einem objektorientierten Datenbankentwurf

23
24
25
26
27
28
29
30
31
32
33
34
35
36

while (result.hasNext()){
p = result.next();
f.add(p);
}

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return f;

Listing 5.30: FormatierungAuslesen.java


Eine bestimmte Formatierung knnen Sie auslesen, indem Sie der Methode get() als Parameter
folgendes Beispielobjekt bergeben:
Formatierung

p = new

F o r m a t i e r u n g ( name ,

null );

Dem Beispielobjekt wurde als Parameter der Name der Formatierung und null als Standardwert
der ArrayList bergeben. Lassen Sie uns dies in der Klasse FormatierungAuslesenEinzeln.java
umsetzen. Die darin enthaltene Methode auslesenEinzeln() liest ein bestimmtes Formatierungsobjekt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

60

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class FormatierungAuslesenEinzeln {


public Formatierung auslesenEinzeln(String name){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
Formatierung fo = new Formatierung();
try {
Formatierung p = new Formatierung(name, null);
ObjectSet<Formatierung> result = db.get(p);

5.3 1:n-Beziehung

23
24
25
26
27
28
29
30
31
32
33

fo = result.next();

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return fo;

}
Listing 5.31: FormatierungAuslesenEinzeln.java

ndern
Drittens ndern wir eine Formatierung, indem wir zuerst das entsprechende Formatierungsobjekt
mit der Methode get() auslesen, mit der Methode setName() den Namen der Formatierung
verndern und anschlieend wieder mit der Methode set() in der Datenbank speichern:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

package Kap05;
import
import
import
import
import

Datenbankentwurf.Formatierung;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;

public class FormatierungAendern {


public void aendern(Formatierung f, Formatierung fo){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<Formatierung> result = db.get(f);
Formatierung p = result.next();
String name = fo.getName();
p.setName(name);
db.set(p);
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

61

5 Beziehungen in einem objektorientierten Datenbankentwurf

29
30

Listing 5.32: FormatierungAendern.java

Lschen
Und viertens lschen wir unser Formatierungsobjekt mit der Methode delete() wieder aus der
Datenbank, wobei nicht automatisch die darin enthaltene ArrayList, die die Texte enthlt, gelscht wird. Die ArrayList wird im Konstruktor mit Parameter name in der Klasse Formatierung
angelegt, um spter jeder Formatierung, Texte hinzufgen zu knnen. So enthlt jedes Formatierungsobjekt eine ArrayList, auch wenn noch keine Texte hinzugefgt worden sind.
Die ArrayList<Text> des Formatierungsobjektes wird auch nicht mit der folgenden Befehlszeile
gelscht, die vor dem nen der Datenbank eingefgt wird:
Db4o . c o n f i g u r e ( ) . o b j e c t C l a s s ( F o r m a t i e r u n g . c l a s s ) . c a s c a d e O n D e l e t e ( t r u e ) ;
Dies hat folgenden Grund: Die ArrayList knnte weitere Elemente enthalten und die sollen nicht
unabsichtlicherweise gelscht werden. Also: Lschen Sie mit folgender Methode loeschen() der
Klasse FormatierungLoeschen.java ein Objekt der Klasse Formatierung, lschen Sie nur das Formatierungsobjekt und das darin enthaltene Stringobjekt, das den Namen zum Inhalt hat, aber

nicht die auch darin enthaltene ArrayList.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

62

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class FormatierungLoeschen {


public void loeschen(Formatierung f){
Db4o.configure().objectClass(Formatierung.class).
cascadeOnDelete(true);
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<Formatierung> result = db.get(f);
Formatierung p = result.next();
db.delete(p);
} catch (DatabaseFileLockedException e) {

5.3 1:n-Beziehung

27
28
29
30
31
32

e.printStackTrace();
} finally{
db.close();
}

Listing 5.33: FormatierungLoeschen.java


Lassen Sie uns dieses Verhalten anhand eines konkreten Beispiels berprfen: Als Erstes legen wir
in unten stehendem Listing FormatierungOhneTextInDatenbank.java zwei Formatierungsobjekte
mit Namen font1 und font2 an:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

package Kap05;
import Datenbankentwurf.Formatierung;
import Datenbankentwurf.Text;
import java.util.ArrayList;
public class FormatierungOhneTextInDatenbank {
public static void main(String[] args){
FormatierungSpeichern fd = new FormatierungSpeichern();
Formatierung f = new Formatierung("font1");
Formatierung fo = new Formatierung("font2");
fd.speichern(f);
fd.speichern(fo);
}

Listing 5.34: FormatierungOhneTextInDatenbank.java


Wir lesen beide Formatierungsobjekte einschlielich der darin enthaltenen ArrayList mit der
unten stehenden Klasse FormatierungTextAusDatenbank.java wieder aus:

1
2
3
4
5
6
7
8
9

package Kap05;
import Datenbankentwurf.Formatierung;
import Datenbankentwurf.Text;
import java.util.ArrayList;
public class FormatierungTextAusDatenbank {
public static void main(String[] args){

63

5 Beziehungen in einem objektorientierten Datenbankentwurf

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

FormatierungAuslesen fau = new FormatierungAuslesen();


ArrayList<Formatierung> al = fau.auslesen();
for(Formatierung f : al){
/*Name der Formatierung wird ausgegeben:*/
System.out.println("Formatierung: "+ f.getName());
ArrayList<Text> at = f.getText();
/*Anzahl der Textobjekte, die sich in der ArrayList<Text> befinden,
werden ausgegeben:*/
System.out.println("Elemente in der ArrayList: " + at.size());
for(Text t : at){

/*Die Inhalte der Textobjekte werden ausgegeben:*/


System.out.println("Text zu Formatierung: "+ t.getName());

Listing 5.35: FormatierungTextAusDatenbank.java

Ausgabe:
Formatierung: font1
Elemente in der ArrayList: 0
Formatierung: font2
Elemente in der ArrayList: 0
Es wurden zwei Formatierungsobjekte angelegt, die jeweils einen Namen und eine noch leere
ArrayList enthalten.
Bevor wir versuchen wollen, die zwei Objekte mit der Klasse FormatierungLoeschen.java und der
Methode loeschen() zu lschen, erstellen wir eine Klasse ArrayListAuslesen.java mit der Methode
auslesen, die es uns ermglicht, eine ArrayList ohne das Formatierungsobjekt auszugeben. Da es
weder mglich ist, ein Beispielobjekt ArrayList(null) zu erstellen, noch eine generische ArrayList
aus der Datenbank auszulesen, lesen wir eine nicht generische ArrayList mit
ArrayList . c l a s s
aus der Datenbank aus. Vergleichen sie hierzu auch die Ausfhrungen zu Interfaces und Abstrakten Klassen im Kapitel Vererbungsbeziehungen.

1
2

64

package Kap05;

5.3 1:n-Beziehung

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

import
import
import
import
import
import

com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;
java.util.List;

public class ArrayListAuslesen {


public ArrayList<ArrayList> auslesen(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<ArrayList> f = new ArrayList<ArrayList>();
ArrayList li = new ArrayList();
try {
/*Wir lesen eine ArrayList aus:*/
ObjectSet<ArrayList> result = db.get(ArrayList.class);
while (result.hasNext()){
li = result.next();
f.add(li);
}

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return f;

Listing 5.36: ArrayListAuslesen.java


Und tatschlich lassen sich die beiden ArrayListen auch ohne die zugehrigen Formatierungsobjekte mit der Klasse ArrayListAuslesenAusDatenbank.java wieder auslesen:

1
2
3
4
5
6
7
8

package Kap05;
import Datenbankentwurf.Text;
import java.util.ArrayList;
public class ArrayListAuslesenAusDatenbank {
public static void main(String[] args){

65

5 Beziehungen in einem objektorientierten Datenbankentwurf

9
10
11
12
13
14
15
16
17
18
19

ArrayListAuslesen to = new ArrayListAuslesen();


ArrayList<ArrayList> at = to.auslesen();
for(ArrayList a : at){
System.out.println("Gre: "+a.size());
}
}

Listing 5.37: ArrayListAuslesenAusDatenbank.java

Ausgabe:
Gre: 0
Gre: 0
Jetzt lschen wir unsere beiden Formatierungobjekte und anschlieend wollen wir feststellen, ob
tatschlich die ArrayListen in der Datenbank verbleiben:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package Kap05;
import Datenbankentwurf.Formatierung;
public class FormatierungLoeschenAusDatenbank {
public static void main(String[] args){
FormatierungLoeschen fol = new FormatierungLoeschen();
Formatierung f = new Formatierung("font1");
Formatierung fo = new Formatierung("font2");
fol.loeschen(f);
fol.loeschen(fo);
}

Listing 5.38: FormatierungLoeschenAusDatenbank.java


Lesen wir wieder die Formatierungobjekte mit FormatierungTextAusDatenbank.java aus, erhalten wir wie erwartet keine Ausgabe. Diese wurden erwartungsgem gelscht. Lesen wir aber die
ArrayListen mit ArrayListAuslesenAusDatenbank.java aus, stellen wir fest, dass die ArrayListen
nicht gelscht wurden und weiterhin in der Datenbank verbleiben. Dies kann ein gewnschter

66

5.3 1:n-Beziehung

Nebeneekt sein, oder auch nicht.

Ausgabe:
Gre: 0
Gre: 0
Also: berprfen Sie immer, ob auch die Daten gelscht worden sind, die Sie lschen wollten.
Bevor wir aber auch die ArrayList lschen werden, lernen wir zuerst, wie wir unseren Formatierungsobjekten, Textobjekte hinzufgen knnen.

5.3.3 Text zu den Formatierungen hinzufgen


Wie knnen Sie Formatierungsobjekten, Texte hinzufgen? Lassen Sie uns das nahe liegende
versuchen: Wir lesen das Formatierungsobjekt und die ArrayList aus und fgen der ArrayList
mit der Methode add() ein Textobjekt hinzu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

package Kap05;
import
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class FormatierungTextHinzu {


public void addText(Formatierung f, Text t){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<Formatierung> result = db.get(f);
Formatierung p = result.next();
ArrayList<Text> al = p.getText();
al.add(t);
p.setText(al);
db.set(p);
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

67

5 Beziehungen in einem objektorientierten Datenbankentwurf

33
34

Listing 5.39: FormatierungTextHinzu.java


Wir lschen die vorhandene Datenbank. Und wir legen wieder zwei Formatierungsobjekte und
eine Datenbank mit der Klasse FormatierungOhneTextInDatenbank.java an, nmlich font1 und
font2. Wir lesen anschlieend die Formatierungsobjekte mit der Klasse FormatierungTextAusDatenbank.java aus:

Ausgabe:
Formatierung: font1
Elemente in der ArrayList: 0
Formatierung: font2
Elemente in der ArrayList: 0
Genau, wie wir erwartet haben, es wurden alle beiden Formatierungen ausgegeben und die entsprechenden Elemente, die sich in der jeweiligen ArrayList benden. Da wir noch keine Texte
hinzugefgt haben, gibt es auch keine Elemente in der ArrayList.
So kommen wir zum nchsten Schritt: Wir fgen der Formatierung font1 mit der Methode
addText() der Klasse FormatierungTextHinzu.java einen Text mit Inhalt erster Text und einen
Text mit Inhalt zweiter Text hinzu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package Kap05;
import Datenbankentwurf.Formatierung;
import Datenbankentwurf.Text;
public class FormatierungAddTextInDatenbank {
public static void main(String[] args){
FormatierungTextHinzu fa = new FormatierungTextHinzu();
Formatierung f = new Formatierung("font1");
Text t = new Text("erster Text");
Formatierung fo = new Formatierung("font1");
Text te = new Text("zweiter Text");

fa.addText(f,t);
fa.addText(fo,te);

Listing 5.40: FormatierungAddTextInDatenbank.java

68

5.3 1:n-Beziehung

Lesen wir nun die Formatierungsobjekte wieder mit der Klasse FormatierungTextAusDatenbank.java aus, erhalten wir unten stehendes Ergebnis. Und stellen uns die Frage: Ups, was ist
jetzt passiert?
Formatierung: font1
Elemente in der ArrayList: 0
Formatierung: font2
Elemente in der ArrayList: 0
Der Text ist nicht der ArrayList hinzugefgt worden. Es ist also nicht das passiert, was wir
erwartet haben. Fazit: Wir mssen der Datenbank db4o erst mitteilen, sie solle doch bitte der
ArrayList, die sich im Formatierungsobjekt bendet, Elemente hinzufgen. Dies geschieht mit
der folgenden dafr vorgesehenen Befehlszeile:
Db4o . c o n f i g u r e ( ) . o b j e c t C l a s s ( F o r m a t i e r u n g . c l a s s ) . c a s c a d e O n U p d a t e ( t r u e ) ;
Diese Befehlszeile muss vor nen der Datenbank durchgefhrt werden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

package Kap05;
import
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class FormatierungTextCascade {


public void addText(Formatierung f, Text t){
Db4o.configure().objectClass(Formatierung.class).cascadeOnUpdate(true);
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<Formatierung> result = db.get(f);
Formatierung p = result.next();
ArrayList<Text> al = p.getText();
al.add(t);
p.setText(al);
db.set(p);
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();

69

5 Beziehungen in einem objektorientierten Datenbankentwurf

33
34
35

Listing 5.41: FormatierungTextCascade.java


Fgen wir nun mit dieser genderten Methode addText() der Klasse FormatierungTextCascade.java der Formatierung font1 zwei Texte hinzu, erhalten wir das gewnschte Ergebnis:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

package Kap05;
import Datenbankentwurf.Formatierung;
import Datenbankentwurf.Text;
public class FormatierungTextCascadeInDatenbank {
public static void main(String[] args){
FormatierungTextCascade fa = new FormatierungTextCascade();
Formatierung f = new Formatierung("font1");
Text t = new Text("erster Text");
Formatierung fo = new Formatierung("font1");
Text te = new Text("zweiter Text");
fa.addText(f,t);
fa.addText(fo, te);
}

Listing 5.42: FormatierungTextCascadeInDatenbank.java

Ausgabe:
Formatierung: font2
Elemente in der ArrayList: 0
Formatierung: font1
Elemente in der ArrayList: 2
Text zu Formatierung: erster Text
Text zu Formatierung: zweiter Text
Der ArrayList des Formatierungsobjektes font1 wurden beide Textobjekte hinzugefgt.
Zusammenfassend lsst sich also sagen: Enthalten Objekte eine ArrayList, wird diese nicht automatisch mit verndert. Wollen Sie Elemente der ArrayList hinzufgen, mssen Sie dies separat
festlegen.

70

5.3 1:n-Beziehung

5.3.4 Textobjekte aus der ArrayList des Formatierungsobjektes wieder


entfernen
Wie lschen wir den Text erster Text aus der ArrayList des Formatierungsobjektes mit Namen
font1 wieder? Der folgende Versuch den Text mit der folgenden Befehlszeile:
Db4o . c o n f i g u r e ( ) . o b j e c t C l a s s ( F o r m a t i e r u n g . c l a s s ) . c a s c a d e O n U p d a t e ( t r u e ) ;
aus der ArrayList zu entfernen gelingt, wenn Sie den zu entfernenden Text aus der Datenbank
auslesen, bevor Sie ihn aus der ArrayList mit der Methode remove() entfernen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

package Kap05;
import
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class FormatierungTextRemoveCascade {


public void removeText(Formatierung f, Text t){
Db4o.configure().objectClass(Formatierung.class).cascadeOnUpdate(true);
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<Formatierung> result = db.get(f);
Formatierung p = result.next();
ArrayList<Text> al = p.getText();
/*Sie mssen zuerst das Textobjekt, das Sie aus der ArrayList
entfernen wollen, aus der Datenbank auslesen, um das
entsprechende Objekt in der Datenbank zu referenzieren.*/
ObjectSet<Text> resultText = db.get(t);
Text te = resultText.next();
/*Danach knnen Sie das ausgelesene Textobjekt aus der
ArrayList mit der Methode remove() entfernen.*/
al.remove(te);
p.setText(al);
db.set(p);
} catch (DatabaseFileLockedException e) {
e.printStackTrace();

71

5 Beziehungen in einem objektorientierten Datenbankentwurf

40
41
42
43
44

} finally{
db.close();
}

Listing 5.43: FormatierungTextRemoveCascade.java

Wir wenden die oben stehende Methode removeText() der Klasse FormatierungTextRemoveCascade.java in unten stehender Klasse FormatierungTextLoeschenInDatenbank.java an:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

package Kap05;
import Datenbankentwurf.Formatierung;
import Datenbankentwurf.Text;
public class FormatierungTextLoeschenInDatenbank {
public static void main(String[] args){
FormatierungTextRemoveCascade fa =
new FormatierungTextRemoveCascade();
Formatierung f = new Formatierung("font1", null);
Text t = new Text("erster Text");
fa.removeText(f,t);
}

Listing 5.44: FormatierungTextLoeschenInDatenbank.java

Und die Ausgabe auf der Konsole entspricht unseren Erwartungen: Der Text mit Inhalt erster
Text wurde aus der ArrayList, die sich in dem Formatierungsobjekt mit Namen font1 bendet,
wieder gelscht.

Ausgabe:
Formatierung: font1
Elemente in der ArrayList: 1
Text zu Formatierung: zweiter Text
Formatierung: font2
Elemente in der ArrayList: 0

72

5.3 1:n-Beziehung

5.3.5 Texte auch aus der Datenbank entfernen


Wurde bei diesem Vorgang das Textobjekt auch aus der Datenbank gelscht? Oder nur aus der
ArrayList entfernt? Dieser Frage werden wir jetzt nachgehen. Wir erstellen eine Klasse mit einer
Methode, die unabhngig von den Formatierungen, Texte ausliest.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

package Kap05;
import
import
import
import
import
import

Datenbankentwurf.Text;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class TextOhneFormatierungAuslesen {


public ArrayList<Text> auslesen(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Text> f = new ArrayList<Text>();
try {
Text t = new Text(null);
ObjectSet<Text> result = db.get(t);
while (result.hasNext()){
t = result.next();
f.add(t);
}

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return f;

Listing 5.45: TextOhneFormatierungAuslesen.java


Wenden wir die Methode auslesen() der Klasse TextOhneFormatierungAuslesen.java an und lesen
alle Textobjekte aus der Datenbank, stellen wir fest, dass sich das Objekt Text mit Inhalt erster
Text nach wie vor in der Datenbank bendet. Und das obwohl wir den Text aus der ArrayList
des Formatierungsobjektes mit Namen font1 entfernt haben.

73

5 Beziehungen in einem objektorientierten Datenbankentwurf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

package Kap05;
import Datenbankentwurf.Text;
import java.util.ArrayList;
public class TextOhneFormatierungAusDatenbank {
public static void main(String[] args){
TextOhneFormatierungAuslesen to = new TextOhneFormatierungAuslesen();
ArrayList<Text> at = to.auslesen();
for(Text t: at){
System.out.println("Name des Textes: "+t.getName());
}
}

Listing 5.46: TextOhneFormatierungAusDatenbank.java

Ausgabe:
Name des Textes: zweiter Text
Name des Textes: erster Text
Wre dies ein Artikel und Sie htten eine Rechnung gelscht, wren Sie jetzt berglcklich. Aber
in unserem Fall ist so ein allein existierender Text nur Datenmll und wir wollen diesen Text nicht
nur aus der ArrayList entfernen, sondern auch aus der Datenbank lschen. Die bereits bekannte
Methode delete() lscht unser Textobjekt, nachdem es aus der ArrayList entfernt wurde. In der
Klasse FormatierungNurTextLoeschen.java werden beide Vorgnge hintereinander durchgefhrt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

74

package Kap05;
import
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class FormatierungNurTextLoeschen {


public void removeText(Formatierung f, Text t){
Db4o.configure().objectClass(Formatierung.class).cascadeOnUpdate(true);

5.3 1:n-Beziehung

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<Formatierung> result = db.get(f);
Formatierung p = result.next();
ArrayList<Text> al = p.getText();
ObjectSet<Text> resultText = db.get(t);
Text te = resultText.next();
/*Zuerst muss der Text aus der ArrayList<Text>
mit der Methode remove() entfernt werden.*/
al.remove(te);
p.setText(al);
/*Danach mssen Sie den Text auch mit der Methode delete()
aus der Datenbank lschen.*/
db.delete(te);
db.set(p);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.47: FormatierungNurTextLoeschen.java


Wir lschen unsere Datenbank und erstellen eine neue Datenbank mit der Klasse FormatierungOhneTextInDatenbank.java und der Klasse FormatierungTextCascadeInDatenbak.java. Diese enthlt wieder unsere Formatierungsobjekte font1 und font2 und die dazugehrigen Texte
erster Text und zweiter Text . Wir lschen erneut den Text erster Text aus dem Formatierungsobjekt font1 , dieses Mal mit mit der Methode removeText() der Klasse FormatierungNurTextLoeschen.java:

1
2
3
4
5
6
7
8
9
10
11

package Kap05;
import Datenbankentwurf.Formatierung;
import Datenbankentwurf.Text;
public class FormatierungNurTextLoeschenAusDatenbank {
public static void main(String[] args){
FormatierungNurTextLoeschen fa = new FormatierungNurTextLoeschen();

75

5 Beziehungen in einem objektorientierten Datenbankentwurf

Formatierung f = new Formatierung("font1", null);


Text t = new Text("erster Text");

12
13
14
15
16
17
18

fa.removeText(f, t);
}

Listing 5.48: FormatierungNurTextLoeschenAusDatenbank.java


Lesen wir wieder die Text- und Formatierungsobjekte aus, stellen wir fest, dass sowohl der Text
aus der ArrayList entfernt wurde als auch aus der Datenbank. Wie folgende zwei Abfragen beweisen: Die erste Abfrage liest die Formatierungsobjekte und ihre Bestandteile mit der Klasse
FormatierungTextAusDatenbank.java aus:
Formatierung: font2
Elemente in der ArrayList: 0
Formatierung: font1
Elemente in der ArrayList: 1
Text zu Formatierung: zweiter Text
Und die Zweite Abfrage mit der Klasse TextOhneFormatierungAusDatenbank.java, die nur die
Textobjekte ausliest, ergibt unten stehende Ausgabe:
Name des Textes: zweiter Text
Wir haben das gewnschte Ergebnis: Es gibt nur noch das Textobjekt mit Inhalt zweiter Text in
unser Datenbank.

5.3.6 Ergnzende Bemerkungen zum Lschvorgang von Objekten der Klasse


Formatierung
Wir wollen uns jetzt wieder dem Lschen von Objekten der Klasse Formatierung zuwenden. Wir
erinnern uns: Wir haben eine Methode loeschen() in der Klasse TextLoeschen.java erstellt, die
zwar unsere Formatierungsobjekte gelscht hat, aber nicht die darin enthaltene ArrayList. Wie
muss eine Methode aussehen, die das Formatierungsobjekt und all seine Bestandteile lscht?
Sie mssen stufenweise vorgehen: Bei der untersten Ebene anfangen, und zwar bei den Texten,
anschlieend knnen Sie die ArrayList lschen und dann das Formatierungsobjekt selbst. Sie
arbeiten sich sozusagen von unten nach oben vor. Also Vorsicht: Unten stehende Klasse lscht
alle Elemente eines Formatierungsobjektes.

1
2
3
4
5
6
7

76

package Kap05;
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;

5.3 1:n-Beziehung

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

import com.db4o.ext.DatabaseFileLockedException;
import java.util.ArrayList;
public class FormatierungAllesLoeschen {
public void removeFormatierung(Formatierung f){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<Formatierung> result = db.get(f);
Formatierung p = result.next();
ArrayList<Text> al = p.getText();
/*Zuerst werden alle Textobjekte gelscht,*/
for(Text te: al){
db.delete(te);
}
/*dann kann die ArrayList gelscht werden, da
sich in ihr keine Elemente mehr befinden und*/
db.delete(al);
/*zum Schlu wird das Formatierungsobjekt gelscht.*/
db.delete(p);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.49: FormatierungAllesLoeschen.java


Jetzt mssten bei Ihnen alle Warnblinklichter angehen: Wenn ich jetzt aber die Formatierungen
noch brauche? Solange noch Texte darin enthalten sind? Hier kommen wir wieder zu unserem
Stichwort referentielle Integritt. Ich will nicht, dass Daten gelscht werden, die ich spter noch
brauche. Eine mglich Lsung dies zu verhindern, ist eine if-Abfrage, mit der ich vorher abfragen
kann, ob es noch Daten in unserer ArrayList gibt. Sollte dies der Fall sein, wird eine Meldung
auf der Konsole ausgegeben und es ist unmglich das Formatierungsobjekt zu lschen.
Lassen Sie uns dies testen: Wir lschen unsere Datenbank wieder und erstellen - wie oben Formatierungsobjekte mit Inhalt, indem wir zuerst die Klasse FormatierungOhneTextInDatenbank.java und dann die Klasse FormatierungTextCascadeInDatenbank.java durchfhren. Nun
versuchen wir, ob wir die Formatierung font1 mit unten stehender Klasse FormatierungAllesLoeschenAusDatenbank.java, die die if-Abfrage enthlt, lschen knnen.

77

5 Beziehungen in einem objektorientierten Datenbankentwurf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

package Kap05;
import Datenbankentwurf.Formatierung;
import java.util.ArrayList;
public class FormatierungAllesLoeschenAusDatenbank {
public static void main(String[] args){
FormatierungAllesLoeschen fal = new FormatierungAllesLoeschen();
String name = new String("font1");
Formatierung f = new Formatierung(name, null);
FormatierungAuslesenEinzeln a = new FormatierungAuslesenEinzeln();
Formatierung fo = a.auslesenEinzeln(name);
/*Sollte sich noch ein Textobjekt in der ArrayList befinden,
dann soll eine Meldung ausgegeben werden.*/
if(fo.getText().size()!= 0){
System.out.println("Sie knnen dieses " +
"Formatierungsobjekt nicht loeschen!");
/*Befindet sich kein Text mehr in der ArrayList, kann
das Formatierungsobjekt gelscht werden*/
} else{
fal.removeFormatierung(f);

Listing 5.50: FormatierungAllesLoeschenAusDatenbank.java

Ausgabe:
Sie knnen dieses Formatierungsobjekt nicht loeschen!
Es wird also wie gewnscht unsere Fehlermeldung ausgegeben. Wurde aber tatschlich nichts
gelscht? Dies berprfen wir mit Formatierung FormatierungTextAusDatenbank.java und wir
erhalten folgende Ausgabe:
Formatierung: font2
Elemente in der ArrayList: 0
Formatierung: font1

78

5.3 1:n-Beziehung

Elemente in der ArrayList: 2


Text zu Formatierung: erster Text
Text zu Formatierung: zweiter Text
Unsere if-Abfrage hat nach unseren Wnschen funktioniert. Was passiert, wenn wir in oben
stehender Klasse statt font1 , font2 lschen? Sie erhalten keine Fehlermeldung, da das Formatierungsobjekt direkt gelscht wird. Wir wollen sichergehen, dass tatschlich das Formatierungsobjekt und die ArrayList gelscht worden ist und lesen wieder die Daten mit FormatierungTextAusDatenbank.java aus der Datenbank aus und erhalten folgendes Ergebnis:
Formatierung: font1
Elemente in der ArrayList: 2
Text zu Formatierung: erster Text
Text zu Formatierung: zweiter Text
Anschlieend lesen wir noch alle ArrayListen mit der Klasse ArrayListAuslesenAusDatenbank.java
aus unserer Datenbank aus:
Gre: 2
Genau wie erwartet: Es gibt nur noch die ArrayList des Formatierungsobjektes font1 in der Datenbank und die ArrayList mit Gre 0 der Formatierung font2 wurde erfolgreich gelscht.
Fazit: Sie knnen Ebene fr Ebene festlegen, welche Objekte gelscht werden und welche nicht.
Achten Sie also bei jedem Lschvorgang darauf, ob Sie alle Objekte gelscht haben oder nicht.
Jede Stufe muss separat gelscht werden. Dies hat z. B. beim Lschen von Rechnungen groe Vorteile, da nicht automatisch die darin enthaltenen Kunden- und Artikelstammdaten mitgelscht
werden.

5.3.7 Texte ndern


Wir haben Objekte der Klasse Text der ArrayList<Text> hinzugefgt, die sich in einem Objekt
der Klasse Formatierung bendet. So bleibt die Frage wie verndern wir das Textobjekt selbst?
Sie lesen das Textobjekt aus der Datenbank aus, verndern und speichern es dann wieder mit
set() in der Datenbank. So wird das Textobjekt selbst verndert und gleichzeitig auch in der
ArrayList des Formatierungsobjektes.

1
2
3
4
5
6
7
8
9
10
11
12

package Kap05;
import
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class TextSeparatAendern {

79

5 Beziehungen in einem objektorientierten Datenbankentwurf

public void updateText(Text t, String s){

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
try {
ObjectSet<Text> resultText = db.get(t);
t = resultText.next();
t.setName(s);
db.set(t);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 5.51: TextSeparatAendern.java


Wir lschen unsere Datenbank und erstellen wieder eine Neue mit zwei Formatierungsobjekten
und zwei Texten mit den Klassen FormatierungOhneTextInDatenbank.java und FormatierungTextCascadeInDatenbank.java und ndern wie unten stehend das Textobjekt erster Text in
genderter Text und lesen das Ergebnis mit der Klasse FormatierungTextAusDatenbank.java
aus.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package Kap05;
import Datenbankentwurf.Formatierung;
import Datenbankentwurf.Text;
public class TextAendernInDatenbank {
public static void main(String[] args){
TextSeparatAendern fa = new TextSeparatAendern();
Text t = new Text("erster Text");
String s = new String("genderter Text");
fa.updateText(t, s);
}

Listing 5.52: TextAendernInDatenbank.java

80

5.3 1:n-Beziehung

Ausgabe:
Formatierung: font2
Elemente in der ArrayList: 0
Formatierung: font1
Elemente in der ArrayList: 2
Text zu Formatierung: genderter Text
Text zu Formatierung: zweiter Text
Also wie Sie sehen knnen, erhalten wir das gewnschte Ergebnis.

5.3.8 Die Klasse Website


Wie geht es weiter? Wir haben bereits die folgenden Klassen: Verlinkung, Link, PDF, Bild, Text
und Formatierung. Welche Klasse fehlt uns jetzt noch? Die Klasse WebSite. Welche Bestandteile
hat normalerweise eine Webseite? Sie kann einen oder mehrere Texte enthalten, genauso wie
Bilder und PDFs, aber nur einen einzigen Hyperlink. So fgen wir der Klasse WebSite ein Objekt
der Klasse Link hinzu, da eine Webseite jeweils einen Link besitzt und zu einem Link eine
sogenannte has-a-Beziehung deniert. Weiterhin enthlt sie jeweils eine ArrayList fr Texte,
Bilder und PDFs, da die Webseite zu diesen Elementen jeweils eine 1:n-Beziehung besitzt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

package Datenbankentwurf;
import java.util.ArrayList;
public class WebSite {
private
private
private
private
private
private

Link link;
ArrayList<Text> text;
ArrayList<Bild> bild;
ArrayList<PDF> pdf;
String reihenfolge;
String ebene;

public WebSite(){
}
public WebSite(Link link, ArrayList<Text> text,
ArrayList<Bild> bild, ArrayList<PDF> pdf,
String reihenfolge, String ebene) {
this.link = link;
this.text = text;
this.bild = bild;
this.pdf = pdf;
this.reihenfolge = reihenfolge;
this.ebene = ebene;

81

5 Beziehungen in einem objektorientierten Datenbankentwurf

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

public Link getLink() {


return link;
}
public void setLink(Link link) {
this.link = link;
}
public ArrayList<Text> getText() {
return text;
}
public void setText(ArrayList<Text> text) {
this.text = text;
}
public ArrayList<Bild> getBild() {
return bild;
}
public void setBild(ArrayList<Bild> bild) {
this.bild = bild;
}
public ArrayList<PDF> getPdf() {
return pdf;
}
public void setPdf(ArrayList<PDF> pdf) {
this.pdf = pdf;
}
public String getReihenfolge() {
return reihenfolge;
}
public void setReihenfolge(String reihenfolge) {
this.reihenfolge = reihenfolge;
}
public String getEbene() {
return ebene;
}
public void setEbene(String ebene) {
this.ebene = ebene;
}

82

5.4 m:n-Beziehung

78
79

}
Listing 5.53: WebSite.java

Soweit stimmen Sie mir bestimmt zu. Was bedeuten aber die zwei Strings reihenfolge und ebene?
Mit dem String reihenfolge wird die Reihenfolge der Links festgelegt. So steht z. B. der Link Home
an erster Stelle und der Link Produkte an zweiter Stelle. So geben Sie bei Home die Reihenfolge
1 ein und bei Produkte die Reihenfolge 2. Gibt es innerhalb den Produkten wieder Unterpunkte,
wie z. B. Bcher und DVDs, dann knnen Sie bei Bcher auch wieder die Reihenfolge 2 eingeben
und bei Ebene dann 1, wohingen Sie bei DVDs die Reihenfolge 2 und die Ebene 2 zuweisen. So
erscheinen die beiden Links fr Bcher und DVDs sobald Sie auf den Link Produkte klicken.

Abbildung 5.3: Hyperlinks oben und links


Im Kapitel Abfragekonzepte werden wir uns genauer anschauen, wie die entsprechenden Abfragen
lauten, die wir dafr brauchen.

5.4 m:n-Beziehung
In unserem Projekt gibt es keine m:n Beziehung, deswegen mchte ich einige andere Beispiele
anfhren: So knnen rzte viele Patienten haben, es knnen aber auch Patienten viele rzte haben. Oder Artikel knnen in mehreren Rechnungen auftauchen, eine Rechnung kann aber
auch verschiedene Artikel beinhalten. So knnte eine vereinfachte Klasse Artikel, eine ArrayList<Rechnung> enthalten und knnte so mehrere Rechnungen speichern.

1
2
3
4

package Kap05;
import java.util.ArrayList;

83

5 Beziehungen in einem objektorientierten Datenbankentwurf

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

public class Artikel {


private String artikelnummer;
private String name;
private ArrayList<Rechnung> rechnung;
public Artikel() {
}
public Artikel(String artikelnummer, String name,
ArrayList<Rechnung> rechnung){
this.artikelnummer = artikelnummer;
this.name = name;
this.rechnung = rechnung;
}
public String getArtikelnummer() {
return artikelnummer;
}
public void setArtikelnummer(String artikelnummer) {
this.artikelnummer = artikelnummer;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<Rechnung> getRechnung() {
return rechnung;
}
public void setRechnung(ArrayList<Rechnung> rechnung) {
this.rechnung = rechnung;
}
}
Listing 5.54: Artikel.java

Die passende vereinfachte Klasse Rechnung knnte die entsprechende ArrayList enthalten, die
Artikel speichert.

84

5.4 m:n-Beziehung

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

package Kap05;
import java.util.ArrayList;
public class Rechnung {
private String rechnungsnummer;
private ArrayList<Artikel> artikel;
public Rechnung() {
}
public Rechnung(String rechnungsnummer,
ArrayList<Artikel> artikel) {
this.artikel = artikel;
this.rechnungsnummer = rechnungsnummer;
}
public String getRechnungsnummer() {
return rechnungsnummer;
}
public void setRechnungsnummer(String rechnungsnummer) {
this.rechnungsnummer = rechnungsnummer;
}
public ArrayList<Artikel> getArtikel() {
return artikel;
}
public void setArtikel(ArrayList<Artikel> artikel) {
this.artikel = artikel;
}
}
Listing 5.55: Rechnung.java

85

6 Abfragekonzepte
Wie wir bereits gesehen haben, gibt es in einer objektorientierten Datenbank keine SQL-Befehle,
sondern entsprechende Methoden und Abfragekonzepte aus db4o. Diese Methoden und Abfragekonzepte sind entweder direkt aus Java entnommen oder basieren auf Java. In diesem Kapitel
werden wir die Abfragekonzepte Query-by-Example, Native Queries und S.O.D.A. nher beleuchten.
Hier ein erster kurzer berblick:
1.

Native Queries: Die Methoden der Programmmiersprache Java werden als Abfragesprache verwendet. Zustzlich stellt db4o einige zustzliche Funktionalitten zur Verfgung,
wie z. B. die Methoden der abstrakten Klasse Predicate des Packages com.db4o.query. Mit
Native Queries knnen Abfragen formuliert werden, die Bedingungen erfllen mssen.

2.

S.O.D.A.: db4o gibt Ihnen ein eigenes Abfragekonzept an die Hand. Die entsprechenden
Methoden nden Sie im Interface Query und Interface Constraint, die sich im Package
com.db4o.query benden. S.O.D.A. umfasst viele Mglichkeiten, Abfragen zu erstellen, die
Datenstze suchen, die bestimmten Bedingungen entsprechen mssen.

3.

Query-by-Example:

Mithilfe von Beispielobjekten werden Daten ausgelesen. Hierbei

kann aber nur entweder nach Objekten gesucht werden, die genau diesem Beispiel entsprechen, oder nach allen Objekten einer Klasse.

6.1 Native Queries


Das Abfragekonzept Native Queries macht die Programmiersprache zur Abfragesprache. Dies hat
folgende Vorteil: Sie brauchen keine SQL-Befehle mehr, in die Programmiersprache Java zu integrieren. Sie knnen direkt mit bekannten Methoden und Hilfsmitteln aus Java Daten speichern
und wieder auslesen. In db4o knnen Sie also immer auf native Methoden der Programmiersprache zurckgreifen. Native Queries eignen sich im Gegensatz zu Queries-by-Example besonders
fr komplexe Abfragen und Abfragen mit Bedingungen.
Zustzlich stellt Ihnen aber auch db4o, z. B. im Package com.db4o.query, die abstrakte Klasse
Predicate mit seinen Methoden zur Verfgung. Die Klasse Predicate macht es Ihnen mglich,
Bedingungen fr Abfragen zu formulieren.

6.1.1 Speichern und Auslesen von Objekten der Klasse WebSite


Bisher haben wir immer einfache Objekte unseres Content-Management-Systems ein- und wieder
ausgelesen. Wie aber werden komplexe Objekte gespeichert und wieder ausgelesen? Und wie
knnen komplexe Objekte ausgelesen werden, die bestimmte Bedingungen erfllen? Dies mchte
ich anhand der Klasse WebSite nher erlutern.
Beginnen wir mit dem Speichern eines Objektes der Klasse WebSite: Wird eine ganze Webseite
abgespeichert, mssen Sie mehrere Speichervorgnge, die logisch zusammengehren, gleichzeitig

87

6 Abfragekonzepte

durchfhren. Es macht keinen Sinn den Text in einer separaten addText()-Methode dem Formatierungsobjekt hinzufgen und dann erst in einer anderen Methode dem WebSite-Objekt. Diese
Vorgnge mssen gleichzeitig erfolgen und zusammen gespeichert oder ausgelesen werden.
Abfragen, die zusammengehren und in einem Schritt durchgefhrt werden sollten, nennt man
Transaktionen. Sollte es zu Problemen kommen, whrend die Datenbank genet ist, knnen
alle Abfragen rckgngig gemacht werden, indem ein so genannter Rollback-Befehl durchgefhrt
wird. Dem Thema Transaktionen wird weiter unten ein ausfhrliches Kapitel gewidmet.
Das Speichern eines Objektes der Klasse WebSite erfolgt in der Klasse WebSiteEin.java in mehreren Schritten:
1. Der Text wird dem Formatierungsobjekt hinzugefgt und anschlieend gespeichert.
2. Der Text wird dem Objekt WebSite hinzugefgt.
3. Die Bilder, die PDFs, die Reihenfolge und die Ebene werden dem Objekt WebSite hinzugefgt
4. Und zum Schlu wird das Objekt WebSite gespeichert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

88

package Kap06;
import
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class WebSiteEin {


public void addWebSite(Link link,
ArrayList<Formatierung> formatierung,
ArrayList<Bild> bild, ArrayList<PDF> pdf,
String reihenfolge, String ebene){
/*Die Methode cascadeOnUpdate() bentigen wir,
um der ArrayList<Text> Elemente hinzufgen zu knnen.
Die ArrayList<Text> befindet sich innerhalb des
Formatierungsobjektes.*/
Db4o.configure().objectClass(Formatierung.class).
cascadeOnUpdate(true);
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");

6.1 Native Queries

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

WebSite w = new WebSite();


Formatierung form = new Formatierung();
ArrayList<Text> text = new ArrayList<Text>();
try {
/*Wir fgen dem Formatierungsobjekt die neuen Texte
hinzu, indem wird die ArrayList<Formatierung> f
auslesen, die der Methode addWebSite() als Parameter
bergeben wurde.*/
for(Formatierung f : formatierung){
/*Wir erstellen ein Beispielobjekt mit dem
Namen der Formatierung f und lesen das entsprechende
Formatierungsobjekt aus der Datenbank aus.*/
Formatierung fo = new Formatierung(f.getName());
ObjectSet<Formatierung> result = db.get(fo);
form = result.next();
/*Wir lesen fr jedes Formatierungsobjekt f, die
zugehrigen Texte aus,*/
ArrayList<Text> al = f.getText();
for(Text t: al){
/*und wir fgen sie der ArrayList<Text> des aus
der Datenbank ausgelesenen Formatierungsobjektes hinzu.*/
ArrayList<Text> textNeu = form.getText();
textNeu.add(t);
/*Wir bergeben die ArrayList<Text> der Methode setText()
und ndern so das, aus der Datenbank ausgelesene
Formatierungsobjekt.*/
form.setText(textNeu);

/*und wir speichern das genderte Formatierungsobjekt


in der Datenbank. */
db.set(form);

/*Wir fgen dem neuen Objekt WebSite w Texte hinzu, indem


wir nochmals die ArrayList<Formatierung> f auslesen:*/
for(Formatierung f : formatierung){
/*Wir lesen die Texte zuerst aus der ArrayList<Text>
des Formatierungsobjekt f aus,*/
ArrayList<Text> al = f.getText();
for(Text t : al){

89

6 Abfragekonzepte

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

/*anschlieend lesen wir jeden Text aus der Datenbank aus,*/


ObjectSet<Text> result = db.get(t);
Text te = result.next();

/*und fgen die ausgelesenen Text danach der


ArrayList<Text> text hinzu, die dann
mit dem Objekt WebSite w gespeichert wird*/
text.add(te);

/*Wir verndern alle Eigenschaften der WebSite,*/


w.setLink(link);
w.setText(text);
w.setBild(bild);
w.setPdf(pdf);
w.setReihenfolge(reihenfolge);
w.setEbene(ebene);
/*und wir speichern die WebSite als Ganzes in der Datenbank. */
db.set(w);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

Listing 6.1: WebSiteEin.java


Im nchsten Schritt fgen wir unserer Datenbank eine bestimmte WebSite hinzu, nmlich die
WebSite Home, die einen Text, ein Bild und ein PDF beinhaltet. Sie hat die Reihenfolge 1 und
die Ebene lassen wir leer, da wir wollen, dass die WebSite Home Teil der ersten Menleiste ist und
keinen Unterpunkt hat. Vorher mssen wir allerdings wieder die Datenbank lschen und wieder
Formatierungsobjekte mit der Klasse FormatierungOhneTextInDatenbank.java in der Datenbank
speichern.

1
2
3
4
5
6
7
8
9
10

90

package Kap06;
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
java.util.ArrayList;

6.1 Native Queries

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

public class WebSiteEinlesenInDatenbank {


public static void main(String[] args){
Link link = new Link("Home");
Text t = new Text("Erster Text");
ArrayList<Text> at = new ArrayList<Text>();
at.add(t);
Formatierung f = new Formatierung("font1", at);
ArrayList<Formatierung> af = new ArrayList<Formatierung>();
af.add(f);
Bild b = new Bild("BildHome", "Bilder/home.jpg");
ArrayList<Bild> ab = new ArrayList<Bild>();
ab.add(b);
PDF p = new PDF("PDFHome", "Dokumente/home.pdf");
ArrayList<PDF> ap = new ArrayList<PDF>();
ap.add(p);
String reihenfolge = new String("1");
String ebene = new String("");
WebSiteEin w = new WebSiteEin();
w.addWebSite(link, af, ab, ap, reihenfolge, ebene);
}

Listing 6.2: WebSiteEinlesenInDatenbank.java


Wir lesen mit der Methode auslesen() der unten stehenden Klasse WebSiteAuslesen.java alle
Objekte der Klasse WebSite wieder aus.

1
2
3
4
5
6
7
8
9
10
11
12
13

package Kap06;
import
import
import
import
import
import

Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class WebSiteAuslesen {


public ArrayList<WebSite> auslesen(){

91

6 Abfragekonzepte

ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

ArrayList<WebSite> f = new ArrayList<WebSite>();


try {
WebSite w = new WebSite(null, null, null, null, null, null);
ObjectSet<WebSite> result = db.get(w);
while (result.hasNext()){
w = result.next();
f.add(w);
}

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return f;

Listing 6.3: WebSiteAuslesen.java


Wenden wir anschlieend die Methode auslesen() in der folgenden Klasse WebSiteAuslesenAusDatenbank.java an, erhalten wir genau die Daten zurck, die wir eingegeben haben:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

92

package Kap06;
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Bild;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
java.util.ArrayList;

public class WebSiteAuslesenAusDatenbank {


public static void main(String[] args){
WebSiteAuslesen ws = new WebSiteAuslesen();
ArrayList<WebSite> aw = ws.auslesen();
for(WebSite w: aw){
System.out.println("Link: "+ w.getLink().getName());

6.1 Native Queries

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

ArrayList<Text> al = w.getText();
for(Text t :al){
System.out.println("Text: " + t.getName());
}
ArrayList<Bild> ab = w.getBild();
for(Bild b :ab){
System.out.println("Bild: " + b.getName());
}
ArrayList<PDF> ap = w.getPdf();
for(PDF p:ap){
System.out.println("PDF: " + p.getName());
}
System.out.println("Reihenfolge "+ w.getReihenfolge());
System.out.println("Ebene "+ w.getEbene());

Listing 6.4: WebSiteAuslesenAusDatenbank.java

Ausgabe:
Link: Home
Text: Erster Text
Bild: BildHome
PDF: PDFHome
Reihenfolge 1
Ebene
Wurde auch der Text den Formatierungsobjekten korrekt zugewiesen? Ja. Lesen Sie die Formatierungsobjekte mit den zugehrigen Texten aus, indem Sie die Klasse FormatierungTextAusDatenbank.java laufen lassen, erhalten Sie die folgende Ausgabe:
Formatierung: font2
Elemente in der ArrayList: 0
Formatierung: font1
Elemente in der ArrayList: 1
Text zu Formatierung: Erster Text
Die Texte wurden gleichzeitig in dem Formatierungsobjekt mit dem Namen font1 und in dem
WebSiteobjekt mit Namen Home gespeichert.

93

6 Abfragekonzepte

6.1.2 Bedingungen formulieren


Wie knnen wir in db4o Bedingungen formulieren? Die abstrakte Klasse Predicate und seine Methode match() macht es uns mglich einfache und zusammengesetzte Bedingungen fr Abfragen
zu erstellen.

Abfragen mit einfachen Bedingungen


Beginnen wir mit einer einfachen Bedingung: Wir wollen alle Hyperlinks aller Webseiten auslesen,
die auf unserer ersten Menleiste rechts oben erscheinen, wie in unten stehender Abbildung. Wir
brauchen also alle Objekte der Klasse WebSite, fr die die Bedingung "Ebene ist gleich leer"
zutrit.

Abbildung 6.1: Obere Menleiste mit den Hauptmenpunkten


Um die Elemente der Menleiste auslesen zu knnen, brauchen wir die abstrakte Klasse Predicate,
die wir in der API der Datenbank db4o im Package com.db4o.query.Predicate nden, und die
Methode query() des Interfaces ObjectContainer. Hier ein Ausschnitt der db4o-API, der Ihnen
einen kleinen Einblick in die abstrakte Klasse Predicate verschat:

Abbildung 6.2: Auszug aus der API fr db4o: Die abstrakte Klasse Predicate

94

6.1 Native Queries

Wie wird eine Bedingung formuliert? Sie bergeben der Methode query() als Parameter eine
anonyme Klasse Predicate. Was ist eine anonyme Klasse? Bei anonymen Klassen werden zwei
Schritte in einem durchgefhrt: Es wird eine Klasse ohne Namen und ein Objekt erzeugt. Anonyme Klassen gehren zu den inneren Klassen und werden hug in der Programmierung von
graphischen Oberchen verwendet.
In unten stehender Klasse WebSiteAuslesenLinkErste.java erstellen wir als Parameter fr die
Methode query() eine anonyme Klasse Predicate, die die Methode match() berschreibt. Die
Methode match() beinhaltet eine Bedingung. In unserem Fall ermglicht sie, alle Objekte der
Klasse WebSite auszulesen, fr die Folgendes zutrit: die Ebene besitzt keinen Inhalt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

package Kap06;
import
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;
com.db4o.query.Predicate;

public class WebSiteAuslesenLinkErste {


public ArrayList<Link> auslesenLinkErste(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Link> al = new ArrayList<Link>();
try{
ObjectSet<WebSite> result = db.query(/*Hier steht
eine anonyme Klasse als Parameter einer Methode*/
new Predicate<WebSite>() {
/*die Methode match() muss berschrieben werden*/
public boolean match(WebSite webSite){
/*Hier steht die Bedingung: Es sollen alle WebSiteobjekte
ausgewhlt werden, bei denen die Ebene leer ist*/
return webSite.getEbene().equals("");

}
}
);/*Hier steht die zweite Klammer der Methode query() und
danach ein Strichpunkt*/
/*Es werden die entsprechenden Links ausgelesen und der
ArrayList<Link> al hinzugefgt*/

95

6 Abfragekonzepte

while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
}

40
41
42
43
44
45
46
47
48
49
50
51
52
53

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return al;

Listing 6.5: WebSiteAuslesenLinkErste.java


Bevor wir die Methode auslesenLinkErste() anwenden, fgen wir der Datenbank in der Klasse
WebSiteEinlesenWeitere.java drei weitere Objekte der Klasse WebSite hinzu. Die WebSite Bcher
enthlt einen String ebene mit dem Inhalt "1". Diese drfte also beim Anwenden oben stehender
Methode nicht mit ausgelesen werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

96

package Kap06;
import
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
java.util.ArrayList;

public class WebSiteEinlesenWeitere {


public static void main(String[] args){
//Wir lesen die WebSite mit Namen Produkte ein
Link link = new Link("Produkte");
Text t = new Text("TextProdukte");
ArrayList<Text> at = new ArrayList<Text>();
at.add(t);
Formatierung f = new Formatierung("font1", at);
ArrayList<Formatierung> af = new ArrayList<Formatierung>();
af.add(f);
Bild b = new Bild("BildProdukte", "Bilder/produkte.jpg");

6.1 Native Queries

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

ArrayList<Bild> ab = new ArrayList<Bild>();


ab.add(b);
PDF p = new PDF("PDFProdukte", "Dokumente/produkte.pdf");
ArrayList<PDF> ap = new ArrayList<PDF>();
ap.add(p);
String reihenfolge = new String("2");
String ebene = new String("");
WebSiteEin w = new WebSiteEin();
w.addWebSite(link, af, ab, ap, reihenfolge, ebene);
//Wir lesen die WebSite mit Namen DVD ein
Link linkD = new Link("DVD");
Text teD = new Text("DVDText");
ArrayList<Text> ateD = new ArrayList<Text>();
ateD.add(teD);
Formatierung foD = new Formatierung("font2", ateD);
ArrayList<Formatierung> afoD = new ArrayList<Formatierung>();
afoD.add(foD);
Bild biD = new Bild("BildDVD", "Bilder/dvd.jpg");
ArrayList<Bild> abiD = new ArrayList<Bild>();
abiD.add(biD);
PDF pdD = new PDF("PDF DVD", "Dokumente/dvd.pdf");
ArrayList<PDF> apdD = new ArrayList<PDF>();
apdD.add(pdD);
String reihenfolgeD = new String("2");
String ebeneD = new String("2");
w.addWebSite(linkD, afoD, abiD, apdD, reihenfolgeD, ebeneD);
//Wir lesen die WebSite mit Namen Bcher ein
Link linkNeu = new Link("Bcher");
Text te = new Text("TextBcher");
ArrayList<Text> ate = new ArrayList<Text>();
ate.add(te);
Formatierung fo = new Formatierung("font2", ate);
ArrayList<Formatierung> afo = new ArrayList<Formatierung>();
afo.add(fo);

97

6 Abfragekonzepte

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

Bild bi = new Bild("BildBcher", "Bilder/buecher.jpg");


ArrayList<Bild> abi = new ArrayList<Bild>();
abi.add(bi);
PDF pd = new PDF("PDFBcher", "Dokumente/buecher.pdf");
ArrayList<PDF> apd = new ArrayList<PDF>();
apd.add(pd);
String reihenfolgeNeu = new String("2");
String ebeneNeu = new String("1");
w.addWebSite(linkNeu, afo, abi, apd, reihenfolgeNeu, ebeneNeu);
}

Listing 6.6: WebSiteEinlesenWeitere.java


Werden jetzt tatschlich nur die zwei Objekte Home und Produkte ausgegeben? Wir testen
es und starten die folgende Klasse WebSiteAusDatenbankLinkErste.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

package Kap06;
import Datenbankabfragen.WebSiteDaten;
import Datenbankentwurf.Link;
import java.util.ArrayList;
public class WebSiteAusDatenbankLinkErste {
public static void main(String[] args){
WebSiteAuslesenLinkErste ws = new WebSiteAuslesenLinkErste();
ArrayList<Link> aw = ws.auslesenLinkErste();
for(Link l : aw){
System.out.println("Link "+ l.getName());
}
}

Listing 6.7: WebSiteAusDatenbankLinkErste.java

Ausgabe:
Link Home

98

6.1 Native Queries

Link Produkte
Und tatschlich: Es hat geklappt! Unser erster Anwendungsfall fr die anonyme Klasse Predicate
hat funktioniert. Es wurden nur die Daten ausgelesen, die der Bedingung entsprechen.
Sollten Sie nicht nur einen Teil der WebSites auslesen wollen, sondern alle, geht dies mit unten
stehender berschriebener Methode match():

1
2
3
4
5
6
7
8

ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {


public boolean match(WebSite webSite){
return true;
}
);

Listing 6.8: Auslesen aller WebSite mit Native Queries(AlleLinksNative.txt)

Abfragen mit zusammengesetzten Bedingungen


Als Nchstes wollen wir uns zusammengesetzte Bedingungen fr Abfragen nher ansehen: Wir
lesen mithilfe der abstrakten Klasse Predicate und der Methode match() die Unterpunkte unseres Mens aus. Wenn Sie auf den Hyperlink Produkte klicken, soll auf der linken Seite die
entsprechende Unterpunkte Bcher und DVDs erscheinen. Das vollstndige Beispiel mit JSPs
und Servlets wird im Kapitel Unser Content-Management-System ausfhrlich beschrieben. Im
Moment wollen wir uns auf die entsprechenden Abfragen konzentrieren.

Abbildung 6.3: Linke Menleiste mit den Unterpunkten


Zuerst lesen wir die Variable reihenfolge der entsprechenden WebSite aus. Wir bergeben der
Methode auslesenLinkReihenfolge() als Parameter den Namen des Links der WebSite, die ausgewhlt bzw. angeklickt wird. Der Parameter mu nal sein, da von innerhalb der anonymen
Klasse nur auf nale Variablen des Blocks zugegrien werden kann.
Unser Ergebnis muss in diesem Fall zwei Bedingungen erfllen: Erstens muss das gesuchte Objekt
der Klasse WebSite einen Link mit dem Namen des bergegebenen Namen linkName besitzen
und zweitens muss die Ebene des gleichen Objektes leer sein.

99

6 Abfragekonzepte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

package Kap06;
import
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Predicate;
java.util.ArrayList;

public class WebSiteAuslesenLinkReihenfolge {

100

/*Anonyme Klassen knnen nur auf Bestandteile des Blocks zugreifen,


die final sind, deshalb muss der String als final deklariert werden*/
public String auslesenLinkReihenfolge(final String linkName){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
String reihenfolge = new String();
try{
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
/*Es soll das Objekt der Klasse WebSite ausgewhlt werden,
fr das folgende Bedingungen zutrifft:
Der Name ist identisch mit dem Parameter linkName und
die Ebene ist vom Inhalt leer.*/
return webSite.getLink().getName().equals(linkName)
&& webSite.getEbene().equals("");
}
});
/*Die Methode soll die Reihenfolge zurckgeben, fr die
oben stehende Bedingungen zutrifft.*/
WebSite w = result.next();
reihenfolge = w.getReihenfolge();
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}

6.1 Native Queries

50
51
52

return reihenfolge;

Listing 6.9: WebSiteAuslesenLinkReihenfolge.java


Dann brauchen wir die Namen der entsprechenden Links, die Unterpunkte zu unserem Hauptpunkt Produkte aus der Menleiste sind. Der zugehrigen Abfrage auslesenLinkZweite() bergeben wir die Reihenfolge als Parameter und sie muss zwei Bedingungen erfllen: Der String
reihenfolge des gesuchten WebSite-Objektes muss mit dem bergebenen Parameter reihenfolge bereinstimmen und der String Ebene darf nicht leer sein, da es sich um einen Unterpunkt
handelt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

package Kap06;
import
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Predicate;
java.util.ArrayList;

public class WebSiteAuslesenLinkZweite {


/*Anonyme Klassen knnen nur auf Bestandteile des Blocks zugreifen,
die final sind.*/
public ArrayList<Link> auslesenLinkZweite(final String reihenfolge){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Link> al = new ArrayList<Link>();
try{
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
/*Es soll das Objekt der Klasse WebSite ausgewhlt werden,
fr das folgende Bedingungen zutrifft:
Die Reihenfolge ist identisch mit dem Parameter reihenfolge
und die Ebene ist nicht leer (! bedeutet nicht).*/
return webSite.getReihenfolge().equals(reihenfolge)
&& !webSite.getEbene().equals("");
}

101

6 Abfragekonzepte

});

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

/*Die Methode gib alle Objekte der Klasse WebSite zurck, auf
die oben stehende Bedingungen zutreffen.*/
while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
}

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return al;

Listing 6.10: WebSiteAuslesenLinkZweite.java


Wenden wir die zwei oben stehenden Abfragen in der Klasse WebSiteEbeneAuslesen.java an,
erhalten wir als Ergebnis fr den Menpunkt Produkte, den Link mit Namen Bcher und den
Link mit Namen DVD als Ausgabe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package Kap06;
import Datenbankentwurf.Link;
import java.util.ArrayList;
public class WebSiteEbeneAuslesen {
public static void main(String[] args){
WebSiteAuslesenLinkReihenfolge wr =
new WebSiteAuslesenLinkReihenfolge();
String reihenfolge = wr.auslesenLinkReihenfolge("Produkte");
WebSiteAuslesenLinkZweite wz = new WebSiteAuslesenLinkZweite();
ArrayList<Link> al = wz.auslesenLinkZweite(reihenfolge);

for (Link l : al){


System.out.println("Link: "+l.getName());
}

Listing 6.11: WebSiteEbeneAuslesen.java

102

6.1 Native Queries

Ausgabe:
Link: DVD
Link: Bcher
Alles hat hervorragend geklappt. Unsere Abfragen tun genau das, was sie tun sollen.

6.1.3 Komplexe Abfragen


Im Moment sehen aber unsere Seiten noch leer aus. Oder nicht? Jetzt bentigen wir auf unseren
Seiten noch Text. Wie lesen wir den Text unserer Webseiten aus? Und wie gehen wir mit Abfragen
um, die sich nicht nur mit der Klasse Predicate realisieren lassen? In diesem Fall ergnzen wir
unsere Abfrage, um einige Zeilen nativen Code, sprich wir entnehmen der Programmiersprache
Java einige Methoden.
Erinnern wir uns: Beim Speichern wurden Objekte der Klasse Text sowohl den zugehrigen
Objekten der Klasse WebSite als auch denen der Klasse Formatierung zugewiesen. Die entsprechenden Klassen nden Sie in unserem Projekt im Ordner Datenbankentwurf. Bentigen wir
Texte mit den zugehrigen Formatierungen, mssen diese zuerst aus den Objekten der Klasse
WebSite ausgelesen werden, und anschlieend aus denen der Klasse Formatierung. Wobei jedes zurckgegebene Formatierungsobjekt der Methode auslesenText() jeweils nur ein Textobjekt
enthalten darf.
Es werden mehrere Abfragen, die logisch zusammengehren, gleichzeitig ausgefhrt. Abfragen
die zusammengehren, nennt man Transaktionen, die weiter unten in einem separaten Kapitel
ausfhrlich besprochen werden. Dieses komplexe Problem lsen wir mit der Klasse Predicate
und seiner Methode match() und Methoden aus Java. In der Klasse AuslesenText.java und der
Methode auslesenText() wird die entsprechende Vorgehensweise nher erlutert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

package Kap06;
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Predicate;
java.util.ArrayList;

public class AuslesenText {


public ArrayList<Formatierung> auslesenText
(final String linkName){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Formatierung> af = new ArrayList<Formatierung>();
Formatierung f = new Formatierung(null, null);

103

6 Abfragekonzepte

ArrayList<Text> text = new ArrayList<Text>();

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

try{
/*Zuerst wird das Objekt der Klasse WebSite ausgelesen,
dessen Link dem Namen linkname entspricht */
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
return webSite.getLink().getName().equals(linkName);
}
});
/*Aus diesem Objekt WebSite wird die dazugehrige
ArrayList<Text> ausgelesen*/
while (result.hasNext()){
WebSite w = result.next();
text = w.getText();
}
/*Formatierungsobjekte werden ausgelesen*/
ObjectSet<Formatierung> resultFormat = db.get(f);
while (resultFormat.hasNext()){
Formatierung form = resultFormat.next();
/*Es werden die entsprechende Texte der
Formatierungsobjekte ausgelesen*/
ArrayList<Text> at = form.getText();
for(Text t :at){
/*Es werden die Texte der als Parameter bergebenen
ArrayList<Text> text ausgelesen*/
for(Text te : text){
/*Stimmen die Felder Namen von beiden Texten berein,*/
if(t.getName().equals(te.getName())){
/*wird der Text einer neuen ArrayList<Text> hinzugefgt,
die wiederum einem neuen Formatierungsobjekte
bergeben wird */
ArrayList<Text> al = new ArrayList<Text>();
al.add(t);
Formatierung fo = new Formatierung(form.getName(),al);

104

/*Zum Schlu werden die so erstellten Formatierungsobjekte


der ArrayList<Formatierung> hinzugefgt, und diese gibt
die Methode als Rckgabetyp zurck*/
af.add(fo);

6.1 Native Queries

72
73
74
75
76
77
78
79
80
81
82
83

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return af;

Listing 6.12: AuslesenText.java


Mit unten stehender Klasse WebSiteTextAuslesen.java lesen wir die Formatierungen und die
Texte fr die WebSite mit Namen Home wieder aus. Lschen Sie vorher die Datenbank, erstellen zwei Formatierungsobjekte mit der Klasse FormatierungOhneTextInDatenbank.java und
fgen oben stehende drei Objekte der Klasse WebSite mit WebSiteEinlesenInDatenbank.java und
WebSiteEinlesenWeitere.java in die Datenbank ein.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

package Kap06;
import Datenbankentwurf.Formatierung;
import Datenbankentwurf.Text;
import java.util.ArrayList;
public class WebSiteTextAuslesen {
public static void main(String[] args){
AuslesenText a = new AuslesenText();
ArrayList<Formatierung> af = a.auslesenText("Home");
for(Formatierung f :af){
System.out.println("Formatierung: "+ f.getName());
ArrayList<Text> alt = f.getText();
for(Text t :alt){
System.out.println("Text: "+ t.getName());
}

Listing 6.13: WebSiteTextAuslesen.java

105

6 Abfragekonzepte

Ausgabe:
Formatierung: font1
Text: Erster Text
Unsere Methode hat funktioniert, es wird der passende Text und die dazu gehrige Formatierung
zu der WebSite Home ausgelesen.
Unsere Webseite ist beinahe perfekt. Es fehlen nur noch die Bilder und die PDFs, die wir mit der
Methode auslesenEinzeln() der Klasse WebSiteDaten.java auslesen. Diese Methode bendet sich
im Kapitel Unser Content-Management-System , da diese Methode in Bezug auf die inhaltliche
Problemstellung nichts Neues darstellt.

6.1.4 Sortieren
Wie knnen wir unsere Ergebnisse auf- und absteigend sortieren? Mithilfe der abstrakten Klasse
Predicate und dem Interface Comparator. Wir wollen in unserem Content-Management-System
die obere Menleiste absteigend sortieren lassen. Es soll immer das Element mit der Reihenfolge
1, also unser Hyperlink Home, immer ganz links stehen, wie in unten stehender Abbildung.

Abbildung 6.4: Sortierte obere Menleiste

Um dies realisieren zu knnen, erstellen wir wieder eine anonyme Klasse Predicate, der wir die
Bedingung bergeben. Zustzlich erstellen wir eine anonyme Klasse Comparator und berschreiben deren Methode compare(), die es uns mglich macht, die Elemente dem Linknamen nach
aufsteigend zu sortieren. Das Comparator Interface ist in Java eine hug benutzte Mglichkeit,
Elemente eines TreeSets oder einer ArrayList zu sortieren. db4o nutzt dieses Interface. Wir bergeben der Methode query() des Interfaces ObjectContainer als Parameter eine anonyme Klasse
Comparator zusammen mit der anonymen Klasse Predicate. Sie erhalten ein ObjectSet zurck,
das sortierte Elemente enthlt.

106

6.1 Native Queries

q u e r y ( P r e d i c a t e <T a r g e t T y p e>p r e d i c a t e , j a v a . u t i l . Comparator<T a r g e t T y p e>


comparator )
Folgende Klasse gibt eine ArrayList<Link> zurck, deren Elemente aufsteigend dem Namen
nach sortiert sind:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

package Kap06;
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;
com.db4o.query.Predicate;
java.util.Comparator;

public class WebSiteAuslesenLinkErsteSortieren {


public ArrayList<Link> auslesenLinkErste(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Link> al = new ArrayList<Link>();
/*Wir erstellen vom Interface Comparator eine anonyme Klasse und
berschreiben deren Methode compare(), die es uns mglich macht,
die Links dem Namen nach aufsteigend zu sortieren.*/
Comparator<WebSite> comp = new Comparator<WebSite>(){
public int compare(WebSite w, WebSite we){
return w.getLink().getName().compareTo(we.getLink().getName());
}
};
try{
/*Der Methode query() wird sowohl die anonyme Klasse Predicate
als auch die anonyme Klasse Comparator als Parameter bergeben.*/
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
return webSite.getEbene().equals("");
}
}, comp);
/*Die Objekte der Klasse Link werden sortiert aus der Datenbank
ausgelesen und ebenfalls sortiert der ArrayList<Link>
hinzugefgt.*/
while (result.hasNext()){

107

6 Abfragekonzepte

45
46
47
48
49
50
51
52
53
54
55
56
57

WebSite w = result.next();
Link l = w.getLink();
al.add(l);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return al;

Listing 6.14: WebSiteAuslesenLinkErsteSortieren.java


Wir lesen die Elemente mit der folgenden Klasse WebSiteAusDatenbankLinkErsteSortieren.java
aus und erhalten das gewnschte Ergebnis:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

package Kap06;
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Link;
java.util.ArrayList;
java.util.Collections;

public class WebSiteAusDatenbankLinkErsteSortieren {


public static void main(String[] args){
WebSiteAuslesenLinkErsteSortieren ws =
new WebSiteAuslesenLinkErsteSortieren();
ArrayList<Link> aw = ws.auslesenLinkErste();
for(Link l : aw){
System.out.println("Link "+ l.getName());
}
}

Listing 6.15: WebSiteAusDatenbankLinkErsteSortieren.java

Ausgabe:
Link Home

108

6.1 Native Queries

Link Produkte
Dies entspricht aber nicht den Erfordernissen unserer Menleiste, fr unsere Menleiste brauchen
wir Elemente, die nicht aufsteigend, sondern absteigend sortiert sind. Nachdem wir die anonyme
Klasse Comparator implementiert haben, knnen wir mithilfe der Methode reverse() der Klasse
Collections aus dem Package java.util die Reihenfolge der Element umdrehen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

package Kap06;
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;
com.db4o.query.Predicate;
java.util.Collections;
java.util.Comparator;

public class WebSiteAuslesenLinkErsteSortierenAbsteigend {


public ArrayList<Link> auslesenLinkErste(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Link> al = new ArrayList<Link>();
Comparator<WebSite> comp = new Comparator<WebSite>(){
public int compare(WebSite w, WebSite we){
return w.getLink().getName().compareTo(we.getLink().getName());
}
};
try{
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
return webSite.getEbene().equals("");
}
}, comp);
while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
/*Die Methode reverse() der Klasse Collections aus

109

6 Abfragekonzepte

43
44
45
46
47
48
49
50
51
52
53
54
55
56

dem Package java.util, dreht die Reihenfolge der


Elemente einer Liste um. So erhalten Sie eine Liste,
deren Elemente absteigend sortiert sind.*/
Collections.reverse(al);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return al;

Listing 6.16: WebSiteAuslesenLinkErsteSortierenAbsteigend.java


Fhren wir die modizierte Methode auslesenLinkErste() in der unten stehenden Klasse WebSiteAusDatenbankLinkErsteSortierenAbsteigend.java durch, erhalten wir die Reihenfolge der Links,
die wir fr unsere Menleiste brauchen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

package Kap06;
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Link;
java.util.ArrayList;
java.util.Collections;

public class WebSiteAusDatenbankLinkErsteSortierenAbsteigend {


public static void main(String[] args){
WebSiteAuslesenLinkErsteSortierenAbsteigend ws =
new WebSiteAuslesenLinkErsteSortierenAbsteigend();
ArrayList<Link> aw = ws.auslesenLinkErste();
for(Link l : aw){
System.out.println("Link "+ l.getName());
}
}

Listing 6.17: WebSiteAusDatenbankLinkErsteSortierenAbsteigend.java

Ausgabe:

110

6.2 S.O.D.A.

Link Produkte
Link Home

In dieser Reihenfolge bentigen wir die Elemente fr unser Hauptmenleiste, die sich in unserem
Content-Management-System oben bendet.

6.2 S.O.D.A.
S.O.D.A. steht abgekrzt fr Simple Object Database Access und umfasst Methoden und Interfaces, die db4o im Package com.db4o.query zur Verfgung stellt, mit deren Hilfe Sie Abfragen
mit Bedingungen erstellen knnen.
Im Package com.db4o.query nden Sie alle wichtigen Informationen zu den entsprechenden Interfaces, wie z. B. das Interface Query und Constraint. S.O.D.A. stellt neben den Native Queries
zustzliche Abfragemglichkeiten zur Verfgung, wobei allerdings empfohlen wird, Native Queries
den Methoden von S.O.D.A. vorzuziehen.
Verschaen wir uns einen ersten berblick ber das Interfaces Query: Es stellt Ihnen u. a. die
Mglichkeit zur Verfgung, Abfrageergebnisse zu sortieren. Wollen Sie Ihr Ergebnis alphabetisch
aufsteigend sortieren, knnen Sie dies mit orderAscending() tun. Die Methode orderDescending()
sortiert absteigend. Der Methode constrain() knnen Sie als Parameter eine Bedingung bergeben, nach der die Daten aus der Datenbank ausgelesen werden.

Abbildung 6.5: Das Interface Query im Package com.db4o.query

Das Interface Constraint beinhaltet zutzliche Methoden, die Ihnen bei der Formulierung von einfachen und zusammengesetzten Bedingungen hilfreich sein knnen, wie z.B. not(). Die Methode
not() entspricht dem Ausrufezeichen !, das nicht bedeutet.

111

6 Abfragekonzepte

Abbildung 6.6: Das Interface Constraint im Package com.db4o.query

6.2.1 Bedingungen formulieren


Mit den Mitteln von S.O.D.A. werden wir Bedingungen formulieren, die teilweise identisch sein
werden, mit den bereits erstellten Bedingungen aus dem Kapitel Native Queries. Dies soll es
Ihnen ermglichen den direkten Vergleich zu ziehen, zwischen unterschiedlichen Wegen, die zum
gleichen Ergebnis fhren.

Abfragen mit einfachen Bedingungen


Wie knnen wir die Hyperlinks fr die obere Menleiste mit S.O.D.A.-Methoden auslesen? Mithilfe der Methoden constrain(), descend() und execute(). Der Methode constrain() werden Bedingungen bergeben, nach denen die entsprechenden Objekte oder Felder von Objekten durchsucht
werden. Mit der Methode descend() knnen Sie festlegen, auf welchen Bestandteil einer Klasse
die Bedingung angewendet werden soll und mit execute() wird die Abfrage durchgefhrt. In der
Klasse AuslesenOben.java wollen wir alle Objekte der Klasse Link auslesen, auf die die Bedingung
Element ebene ist gleich leer zutrit.

1
2
3
4
5
6
7

package Kap06;
import
import
import
import
import

112

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;

6.2 S.O.D.A.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

import
import
import
import

com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Predicate;
com.db4o.query.Query;
java.util.ArrayList;

public class AuslesenOben {


public ArrayList<Link> auslesenLinkErste(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Link> al = new ArrayList<Link>();
try{
Query query = db.query();
/*Der Methode constrain() wird folgende Bedingung bergeben:
Es sollen alle Elemente der WebSite ausgelesen werden*/
query.constrain(WebSite.class);
/*Die Bedingung wird eingschrnkt:
Die Methode descend() macht es Ihnen mglich, in
dem Element ebene der WebSite zu suchen, unter der
Bedingung, die Sie der Methode constrain() bergeben:
Es sollen nur die Elemente ausgegeben werden, bei denen
die ebene leer ist.*/
query.descend("ebene").constrain("");
/*Die Methode excecute() fhrt die Abfrage aus.*/
ObjectSet<WebSite> result = query.execute();
/*Es werden aus den Objekten der Klasse WebSite nur
alle Links ausgelesen, auf die oben stehende Bedingung
zutrifft. Diese werden der ArrayList<Link> hinzugefgt,
die die Methode als Rckgabetyp zurckgibt.*/
while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return al;

113

6 Abfragekonzepte

57
58

Listing 6.18: AuslesenOben.java


Fhren wir die Abfrage durch, erhalten wir die gewnschte Ausgabe auf der Konsole, nmlich
alle Links, auf die die Bedingung zutrit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package Kap06;
import Datenbankentwurf.Link;
import java.util.ArrayList;
public class AuslesenLinkErste {
public static void main(String[] args){
AuslesenOben ws = new AuslesenOben();
ArrayList<Link> aw = ws.auslesenLinkErste();
for(Link l : aw){
System.out.println("Link "+ l.getName());
}
}

Listing 6.19: AuslesenLinkErste.java

Ausgabe:
Link Home
Link Produkte

Abfragen mit zusammengesetzten Bedingungen


Wir erstellen jetzt Methoden, die es uns mglich machen, Hyperlinks fr die linke Menleiste
auszulesen. Wie geschieht dies? Mit zusammengesetzten Bedingungen, die wir in S.O.D.A. erstellen. Da es in unten stehenden Fllen um Und-Verknpfungen handelt, knnen diese entweder
mit der Methode and() verknpft werden oder sie werden einfach hintereinander ausgefhrt, was
den gleichen Eekt hat. Zustzlich verwenden wir noch die Methode not(), die die gleiche Bedeutung hat wie der logisch Not-Operator. Vergleichen Sie bitte unten stehende Methoden mit
den gleichnamigen aus dem Kapitel Native Queries.
Vorsicht: Sie bergeben der Methode constrain() einen String, und es wird intern nicht berprft,
ob es das entsprechende Feld in der Datenbank gibt oder nicht. Sollten Sie z.B. Link statt link
schreiben, erhalten Sie als Ergebnis eine leere Menge und keine Fehlermeldung. Also achten Sie
auf korrekte Schreibung und berprfen Sie in Ihrer Klasse, wie die Variable genau benannt
wurde.

114

6.2 S.O.D.A.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

package Kap06;
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Constraint;
com.db4o.query.Predicate;
com.db4o.query.Query;
java.util.ArrayList;

public class AuslesenLinks {


/*Die Methode auslesenLinkReihenfolge() liest die
Reihenfolge aus:*/
public String auslesenLinkReihenfolge(String linkName){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
String reihenfolge = new String();
try{
Query query = db.query();
query.constrain(WebSite.class);
/*Es werden zwei Bedingungen mit der Methode and()
verknpft.*/
Constraint c = query.descend("link").descend("name").
constrain(linkName);
query.descend("ebene").constrain("").and(c);
ObjectSet<WebSite> result = query.execute();
WebSite w = result.next();
reihenfolge = w.getReihenfolge();

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return reihenfolge;

/*Die Methode auslesenLinkZweite() liest alle Links aus, die

115

6 Abfragekonzepte

Teil der linken Menleiste sein sollen:*/


public ArrayList<Link> auslesenLinkZweite(String reihenfolge){

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Link> al = new ArrayList<Link>();
try{
Query query = db.query();
query.constrain(WebSite.class);
/*Es werden auch zwei Bedingungen verknpft, indem
sie hintereinander durchgefhrt werden. Dies
hat den gleichen Effekt wie oben stehende Verknpfung
mit der Methode and()*/
query.descend("reihenfolge").constrain(reihenfolge);
/*Die Methode not() entspricht dem Operator !, der
bersetzt nicht bedeutet.*/
query.descend("ebene").constrain("").not();
ObjectSet<WebSite> result = query.execute();
while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
}

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return al;

Listing 6.20: AuslesenLinks.java


Testen wir oben stehende zwei Methoden mit der Klasse AuslesenLinksAusDatenbank.java, erhalten wir die Ausgabe, die wir erwartet haben, nmlich die zwei Unterpunkte des Links mit
Namen Produkte :

1
2
3

package Kap06;
import Datenbankentwurf.Link;

116

6.2 S.O.D.A.

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import java.util.ArrayList;
public class AuslesenLinksAusDatenbank {
public static void main(String[] args){
AuslesenLinks a = new AuslesenLinks();
String reihenfolge = a.auslesenLinkReihenfolge("Produkte");
ArrayList<Link> al = a.auslesenLinkZweite(reihenfolge);
for (Link l : al){
System.out.println("Link: "+ l.getName());
}
}

Listing 6.21: AuslesenLinksAusDatenbank.java

Ausgabe:
Link: DVD
Link: Bcher

Bedingungen mit Vergleichen


Welche Vergleichsmglichkeiten stellt Ihnen S.O.D.A. zur Verfgung? Es sind die Methoden
smaller(), greater(), startsWith(), endsWith(), contains(), identity() und like() des Interfaces
Constraint. Vergleichen Sie hierzu auch den Auszug aus der db4o-API, den Sie weiter oben
nden knnen. Ich will Ihnen die Methoden startsWith() und like() anhand eines Beispiels nher
erlutern. Diese beiden Methoden haben hnliche Funktionalitten, unterscheiden sich aber in
der konkreten Anwendung.
Beginnen wir mit startsWith(): Wir wollen alle Objekte der Klasse WebSite auslesen, die einen
Link enthalten, dessen Name mit dem Grobuchstaben B anfngt. Dies tun wir mit der Methode
auslesenLinkAnfang() der Klasse AuslesenStart.java:

1
2
3
4
5
6
7
8
9
10
11
12

package Kap06;
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Constraint;
com.db4o.query.Predicate;
com.db4o.query.Query;
java.util.ArrayList;

117

6 Abfragekonzepte

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

public class AuslesenStart {


public WebSite auslesenLinkAnfang(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
WebSite w = new WebSite();
try{
Query query = db.query();
query.constrain(WebSite.class);
/*Mit folgender Bedingung suchen Sie nach allen
Objekten der Klasse WebSite, deren Linkname
mit dem Grobuchstaben B anfngt.*/
query.descend("link").descend("name").
constrain("B").startsWith(true);
ObjectSet<WebSite> result = query.execute();
w = result.next();

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return w;

Listing 6.22: AuslesenStart.java


Und tatschlich erhalten wir die gewnschte Ausgabe, nmlich das Objekt WebSite, das den
Link mit Namen Bcher enthlt:

1
2
3
4
5
6
7
8
9
10
11
12

package Kap06;
import Datenbankentwurf.WebSite;
import java.util.ArrayList;
public class StartAusDatenbank {

118

public static void main(String[] args){


AuslesenStart as = new AuslesenStart();
WebSite w = as.auslesenLinkAnfang();
System.out.println("Link: " + w.getLink().getName());

6.2 S.O.D.A.

13
14
15

Listing 6.23: StartAusDatenbank.java

Ausgabe:
Link: Bcher
Achtung: Die Methode startsWith() ist keysensitive und sollten Sie den Grobuchstaben B durch
den Kleinbuchstaben b ersetzen wird eine IllegalStateException geworfen, wie Sie in unten stehender Abbildung sehen knnen, da keine Entsprechung in der Datenbank gefunden wird.

Abbildung 6.7: Es wird eine IllegalStateException geworfen


Fhren wir die gleiche Abfrage mit der Methode like() durch, stellen wir fest, dass die Methode
nicht zwischen Klein- und Grobuchstaben unterscheidet.

1
2
3
4
5
6
7
8
9
10
11
12

package Kap06;
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Constraint;
com.db4o.query.Predicate;
com.db4o.query.Query;
java.util.ArrayList;

119

6 Abfragekonzepte

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

public class AuslesenLike {


public WebSite auslesenLinkAnfang(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
WebSite w = new WebSite();
try{
Query query = db.query();
query.constrain(WebSite.class);
query.descend("link").descend("name").
constrain("b").like();
ObjectSet<WebSite> result = query.execute();
w = result.next();

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return w;

Listing 6.24: AuslesenLike.java


Wie Sie unten stehend bei der Klasse LikeAusDatenbank.java sehen knnen, wird bei der Methode
like() auch bei dem Kleinbuchstaben b der Link Bcher ausgelesen. Die Methode like() ist also
nicht keysensitive.

1
2
3
4
5
6
7
8
9
10
11
12
13

package Kap06;
import Datenbankentwurf.WebSite;
import java.util.ArrayList;
public class LikeAusDatenbank {

120

public static void main(String[] args){


AuslesenLike as = new AuslesenLike();
WebSite w = as.auslesenLinkAnfang();
System.out.println("Link: " + w.getLink().getName());

6.2 S.O.D.A.

14
15

Listing 6.25: LikeAusDatenbank.java

Ausgabe:
Link: Bcher
Sollten Sie aber den Buchstaben b durch eine Buchstaben ersetzen, den es nicht gibt, wird auch
eine IllegalStateException geworfen.

6.2.2 Sortieren
Abfrageergebnisse knnen mit der Methode orderAscending() aufsteigend sortiert werden. Wir
wollen die Hyperlinks auf der linken Seite aufsteigend nach dem Feld ebene sortieren und das
Ergebnis soll wie folgt aussehen:

Abbildung 6.8: Sortierte linke Menleiste


Wir wollen also, dass das Objekt Bcher, das die Reihenfolge 2 und die Ebene 1 hat, sich an erster
Stelle oben bendet, und das Objekt DVD mit der Reihenfolge 2 und der Ebene 2 an zweiter
Stelle. Mit welchen Methoden erreichen wir dies? Mit der Methode orderAscending() und mit der
Methode descend(). Mit der Ersten wird sortiert und mit der Zweiten wird das Feld festgelegt,
nach dem sortiert werden soll. Wie Sie in unten stehender Klasse sehen knnen, werden zuerst
die Bedingungen ausgefhrt und anschlieend die Methode orderAscending().

1
2
3

package Kap06;
import Datenbankentwurf.Link;

121

6 Abfragekonzepte

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

import
import
import
import
import
import
import
import
import

Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Constraint;
com.db4o.query.Predicate;
com.db4o.query.Query;
java.util.ArrayList;

public class Sortieren {


public ArrayList<Link> auslesenLinkZweite(String reihenfolge){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<Link> al = new ArrayList<Link>();
try{
Query query = db.query();
query.constrain(WebSite.class);
query.descend("reihenfolge").constrain(reihenfolge);
query.descend("ebene").constrain("").not();
/*Die Methode orderAscending() sortiert die Objekte
der Klasse WebSite, die der oben stehenden Bedingungen
entsprechen, und zwar aufsteigend nach dem Element ebene.*/
query.descend("ebene").orderAscending();
ObjectSet<WebSite> result = query.execute();
while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return al;
}
}
Listing 6.26: Sortieren.java

122

6.2 S.O.D.A.

6.2.3 Direkter Zugri auf Elemente einer ArrayList


Mit S.O.D.A. haben Sie folgenden besonderen Vorteil: Sie haben einen direkten Zugri auf Elemente einer ArrayList. So knnen Sie in unten stehender Methode auslesenLinkBild() das Objekt
der Klasse WebSite auslesen, das ein Bild mit dem Namen bildName enthlt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

package Kap06;
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Constraint;
com.db4o.query.Predicate;
com.db4o.query.Query;
java.util.ArrayList;

public class ArrayListAus {


public WebSite auslesenLinkBild(String bildName){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
WebSite w = new WebSite();
try{
Query query = db.query();
query.constrain(WebSite.class);
/*Sie knnen direkt auf die ArrayList<Bild> bild der Klasse
WebSite und anschlieend auf die Variable name der Klasse
Bild mit descend() zugreifen. Mit constrain() berprfen
Sie die Variable name auf bereinstimmung mit bildName.*/
query.descend("bild").descend("name").constrain(bildName);

ObjectSet<WebSite> result = query.execute();


w = result.next();
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return w;

Listing 6.27: ArrayListAus.java

123

6 Abfragekonzepte

Wir lesen in der Klasse ArrayListAusDatenbank.java ein bestimmtes Objekt aus. Nmlich ein
Objekt der Klasse WebSite, das ein Bild mit dem Namen BildProdukte enthlt. Wir erhalten als
Antwort, dass dies auf die WebSite Produkte zutrit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package Kap06;
import Datenbankentwurf.WebSite;
public class ArrayListAusDatenbank {
public static void main(String[] args){
ArrayListAus aa = new ArrayListAus();
WebSite w = aa.auslesenLinkBild("BildProdukte");
System.out.println("Linkname: " +w.getLink().getName());
}

Listing 6.28: ArrayListAusDatenbank.java

Ausgabe:
Linkname: Produkte

6.3 Query-by-Example
Im Kapitel Erste Datenbankabfragen in db4o haben wir das Abfragekonzept Query-by-Example
bereits ausfhrlich kennen gelernt. Sie erstellen ein Beispielobjekt und nach diesem wird in der
Datenbank gesucht. Diese Abfragemethode ndet seine Grenzen, sobald Sie nach bestimmten Daten suchen, die Bedingungen erfllen mssen. Mssen Abfragen Bedingungen erfllen, bentigen
wir die Abfragekonzepte Native Queries und S.O.D.A..
Query-by-Example stellt Ihnen eine weitere Funktionalitt zur Verfgung: Sie knnen nach einem
Element, das sich innerhalb einer ArrayList bendet, suchen. Den Zugri auf Elemente einer
ArrayList werden wir uns im nchsten Abschnitt nher ansehen.

6.3.1 Zugri auf Elemente einer ArrayList


Wie knnen Sie mithilfe von Query-by-Example Elemente auslesen, die sich innerhalb einer ArrayList eines Objektes benden? Nehmen wir an, Sie suchen nach einer Website, die ein bestimmtes Bild enthlt. Sie erstellen ein Beispielobjekt eines Bildobjektes, dieses bergeben Sie einer
ArrayList<Bild>, das Sie dann wiederum einem Beispielobjekt der Klasse WebSite bergeben.
Unten stehend nden Sie die entsprechende Klasse ArrayListAuslesenExample.java:

1
2

package Kap06;

124

6.3 Query-by-Example

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

import
import
import
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Predicate;
java.util.ArrayList;

public class ArrayListAuslesenExample {


public ArrayList<WebSite> auslesenLinkBild(String bildName){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
WebSite w = new WebSite();
ArrayList<WebSite> we = new ArrayList<WebSite>();
try{
/*Sie erstellen ein Beispielobjekt eines Bildes mit bildName
und fgen dieses Bild einer ArrayList<Bild> hinzu,*/
Bild bild = new Bild(bildName, null);
ArrayList<Bild> b = new ArrayList<Bild>();
b.add(bild);
/*und Sie bergeben die ArrayList einem Beispielobjekt der
Klasse WebSite.*/
w = new WebSite(null, null, b, null, null, null);

/*Jetzt wird nach allen Entsprechungen des Beispielobjektes w


in der Datenbank gesucht.*/
ObjectSet<WebSite> result = db.get(w);
while (result.hasNext()){
w = result.next();
we.add(w);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return we;

Listing 6.29: ArrayListAuslesenExample.java

125

6 Abfragekonzepte

Wir lesen das Objekt der Klasse WebSite aus, das als Element ein Bild mit Namen BildProdukte
enthlt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package Kap06;
import Datenbankentwurf.WebSite;
import java.util.ArrayList;
public class ArrayListAusDatenbankExample {
public static void main(String[] args){
ArrayListAuslesenExample aa = new ArrayListAuslesenExample();
ArrayList<WebSite> we = aa.auslesenLinkBild("BildProdukte");
for(WebSite w:we){
System.out.println("Linkname: " +w.getLink().getName());
}
}

Listing 6.30: ArrayListAusDatenbankExample.java

Ausgabe:
Linkname: Produkte

126

7 Aktivierungstiefe, Update-Tiefe und Tiefe


Objektgraphen

7.1 Aktivierungstiefe und Tiefe Objektgraphen


Tiefe Objektgraphen? Was stellen Sie sich darunter vor? Es ist halb so geheimnisvoll, wie es
klingt. Klassen besitzen has-a-Beziehungen, so hat z. B. unsere WebSite Bilder und diese knnte
theoretisch wieder ein Objekt enthalten und so weiter und so weiter............. Und so ist bereits
ein Tiefer Objektgraph entstanden. So einfach!
Was versteht man unter Aktivierungstiefe? Es sind Objekte einer bestimmten Ebene, die bei einer
Abfrage in den Arbeitsspeicher von db4o geladen werden. Warum sollen nur bestimmte Objekte
aktiviert werden? Da dies ansonsten bei groen Datenmengen sehr schnell zu Problemen mit dem
Arbeitsspeicher fhren wrde. Wie knnen die verschiedenen Ebenen unserer Objekte aktiviert
werden? Mit der Methode activationDepth(), der Sie als Parameter eine Zahl bergeben.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

package Kap07;
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;

public class WebSiteAuslesenActivation {


public ArrayList<WebSite> auslesen(){
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
ArrayList<WebSite> f = new ArrayList<WebSite>();
try {
db.ext().configure().activationDepth(1);
WebSite w = new WebSite(null, null, null, null, null, null);
ObjectSet<WebSite> result = db.get(w);
while (result.hasNext()){

127

7 Aktivierungstiefe, Update-Tiefe und Tiefe Objektgraphen

29
30
31
32
33
34
35
36
37
38
39
40

w = result.next();
f.add(w);

} catch (DatabaseFileLockedException e) {
e.printStackTrace();
} finally{
db.close();
}
return f;

Listing 7.1: WebSiteAuslesenActivation.java


Der Standardwert fr die Aktivierungstiefe betrgt 5. Setzen wir die Aktivierungstiefe auf 0 wird
eine NullPointerException geworfen. Setzen wir die Aktivierungstiefe auf 1 erhalten wir mit der
Klasse AuslesenActivation.java folgende Ausgabe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

package Kap07;
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Bild;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
java.util.ArrayList;

public class AuslesenActivation {

128

public static void main(String[] args){


WebSiteAuslesenActivation ws = new WebSiteAuslesenActivation();
ArrayList<WebSite> aw = ws.auslesen();
for(WebSite w: aw){
System.out.println("Link: "+ w.getLink().getName());
ArrayList<Text> al = w.getText();
for(Text t :al){
System.out.println("Text: " + t.getName());
}
ArrayList<Bild> ab = w.getBild();
for(Bild b :ab){
System.out.println("Bild: " + b.getName());
}

7.1 Aktivierungstiefe und Tiefe Objektgraphen

31
32
33
34
35
36
37
38
39
40
41

ArrayList<PDF> ap = w.getPdf();
for(PDF p:ap){
System.out.println("PDF: " + p.getName());
}
System.out.println("Reihenfolge "+ w.getReihenfolge());
System.out.println("Ebene "+ w.getEbene());

Listing 7.2: AuslesenActivation.java

Ausgabe:
Link: null
Reihenfolge 2
Ebene 2
Link: null
Reihenfolge 1
Ebene
Link: null
Reihenfolge 2
Ebene 1
Link: null
Reihenfolge 2
Ebene
Grundstzlich werden bei der Aktivierungstiefe 1 das Objekt selbst, die darin enthaltenen Strings,
primitiven Elemente und Objekte aktiviert. In der oberen Ausgabe sehen Sie die Strings Reihenfolge und Ebene, die mit ihren Werten ausgegeben werden. Das darin enthaltene Objekt Link
wird mit dem Wert null aktiviert. So werden in unserem Beispiel alle Stringobjekte der Klasse
WebSite mit ihren Werten aktiviert und die Objekte der Klasse Link mit dem Wert null. Die
ArrayListen fr die Texte, Bilder und PDFs werden bei der Aktivierungstiefe 1 nicht aktiviert.
Setzen wir die Aktivierungstiefe auf 2 werden alle Elemente ausgegeben, da als nchste Stufe die
ArrayListen und ihre Objekte und die darin enthaltenen String-Objekte aktiviert werden.

Ausgabe:
Link: DVD
Text: DVDText
Bild: DVD
PDF: PDF DVD
Reihenfolge 2
Ebene 2
Link: Home
Text: Erster Text

129

7 Aktivierungstiefe, Update-Tiefe und Tiefe Objektgraphen

Bild: BildHome
PDF: PDFHome
Reihenfolge 1
Ebene
Link: Bcher
Text: TextBcher
Bild: BildBcher
PDF: PDFBcher
Reihenfolge 2
Ebene 1
Link: Produkte
Text: TextProdukte
Bild: BildProdukte
PDF: PDFProdukte
Reihenfolge 2
Ebene
Dieses Ergebnis erhalten Sie auch ohne explizites Festlegen der Aktivierungstiefe, da die Standardaktivierungstiefe 5 betrgt und somit hher ist, als die soeben erstellte.

7.2 Aktivierungstiefe und die LinkedList


Verwenden Sie eine LinkedList, ist ein anderes Verhalten in Bezug auf die Aktivierungstiefe zu
beobachten. Da jedes Element innerhalb einer LinkedList eine Referenz zum nchsten Element besitzt, wird jedem darin enthaltenen Element eine separate Tiefe zugewiesen. Also: Jedes Element
einer LinkedList beinhaltet ein Element der nchsten Ebene, sprich es gibt eine has-a-Beziehung
zwischen den Elementen einer LinkedList. Wohingegen allen Elementen einer ArrayList eine einzige Tiefe zugewiesen wird.
Lassen Sie mich dies anhand eines Beispiels nher erlutern: Nehmen wir einmal an, Sie haben
sowohl in einer LinkedList als auch in einer ArrayList 5 Elemente. Verlassen Sie sich jetzt auf
die Standardaktivierungstiefe von 5, ist dies bei einer ArrayList kein Problem, da alle Elemente
der ArrayList in den Arbeitsspeicher geladen werden, wohingegen es bei einer LinkedList nur die
ersten 3 Elemente sind.

7.3 Update-Tiefe
Erinnern wir uns an die Methode cascadeOnUpdate(), die es uns ermglichte, einer ArrayList, die
sich in einem Objekt bendet, Elemente hinzufgen. Es gibt fr diese Methode eine Entsprechung
im Interface ExtObjectContainer: die Update-Tiefe. Die Ebene der ArrayList muss aktiviert
werden und da es sich hier um ein Update handelt, spricht man von der Update-Tiefe. Die
entsprechende Zeile, die - wie bei der Aktivierungstiefe - in den try-Block gehrt, lautet wie
folgt:
db . e x t ( ) . c o n f i g u r e ( ) . u p d a t e D e p t h ( 1 ) ;
Eine Update-Tiefe von 0 wrde wiederum bedeuten, dass der ArrayList keine Elemente hinzugefgt werden. Im Kapitel Embedded-Modus in einem Web-Projekt werden wir sehen, dass die
Update-Tiefe die Methode cascadeOnUpdate() im Embedded-Modus ersetzt.

130

7.4 Transparente Aktivierung

7.4 Transparente Aktivierung


Die Transparente Aktivierung ist ein neuer wichtiger Bestandteil von db4o, der zum Zeitpunkt
des Erstellens dieses Buches noch in der Planungs- und Umsetzungsphase war. Die Transparente
Aktivierung soll Objekte in den Arbeitsspeicher laden, die noch nicht aktiviert wurden, die aber
bentigt werden. Der Programmierer soll von der manuellen Aktivierung der Objekte entlastet
werden. Zu diesem Thema knnen Sie sich auf der db4o-Website auf dem Laufenden halten. Dort
gibt es auch in regelmigen Abstnden neue Versionen von db4o zum Herunterladen.

131

8 Exkurs: Threads und Multithreading


An dieser Stelle mchte ich einen Ausug zu den Thread-Grundlagen machen, da dieses Wissen eine wichtige Voraussetzung fr das Verstndnis der Verwendung von Semaphores in db4o
darstellt, die im Kapitel Transaktionen besprochen werden. Zustzlich werden Ihnen die Ausfhrungen im Kapitel zum Thema Client-Server-Modus von Nutzen sein.
Was sind Threads? Threads (deutsch: Fden) sind Aktivitten, wie z. B. Datenbankabfragen,
die vorgeben gleichzeitig abzulaufen, die sich aber tatschlich in der Abarbeitung abwechseln. So
kann es sein, dass bei mehreren Threads, die gleichzeitig durchgefhrt werden, zuerst der erste
zu einem drittel durchgefhrt und dann der nchste zu einem drittel usw. So wird dem Benutzer
vorgegaukelt, dass Prozesse, wie z. B. Programme gleichzeitig ablaufen, was sie aber tatschlich
nicht tun.
Theoretisch gibt es die Mglichkeit, die Reihenfolge der einzelnen Threads zu beeinussen, indem Sie die Prioritten der Threads festlegen. Dieses Verhalten ist aber plattformabhngig, so
haben Sie keinerlei Garantie, dass die Reihenfolge der Threads tatschlich einem bestimmten
gewnschten Verhalten entspricht. Die Prioritt knnen Sie mit setPriority() festlegen und es
gibt drei verschiedene Prioritten, die Sie festlegen knnen: Die Standardprioritt liegt bei 5
(Thread.NORM_PRIORITY), die maximale bei 10 (Thread.MAX_PRIORITY) und die minimale bei 1 (Thread.MIN_PRIORITY).
Threads lassen sich synchronisieren, sprich es kann festgelegt werden, dass die Teilprozesse hintereinander ablaufen. Ein Thread wartet also bis der eine Thread fertig ist und luft erst im
Anschluss.

8.1 Erstellung eines Threads


Wie wird ein Thread erstellt? Es gibt zwei Mglichkeiten: Entweder durch Implementierung des
Runnable Interface oder durch eine Vererbungsbeziehung mit der Klasse Thread.

8.1.1 Mithilfe des Runnable Interfaces


Das Interface Runnable ist Teil des Package java.lang und enthlt eine Methode run(), die implementiert werden muss, wenn Sie einen Thread mithilfe dieses Interfaces erstellen wollen. Die
Instanziierung erfolgt in diesem Fall in 2 Schritten: Erstens wird eine Instanz der neuen Klasse
erstellt und zweitens wird diese einem neuen Threadobjekt als Parameter bergeben.
Wir erstellen also unseren ersten Thread mit dem Namen MeinFaden.java und nachdem wir ihn
gestartet haben, erhalten wir unten stehende Ausgabe:

1
2
3
4
5
6
7

package Kap08;
public class MeinFaden implements Runnable{
public static void main(String[] args){
/*Es wird eine Instanz der Klasse MeinFaden erstellt.*/

133

8 Exkurs: Threads und Multithreading

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

MeinFaden meinFaden = new MeinFaden();


/*Es wird ein Threadobjekt erstellt, dem das Objekt
meinFaden als Parameter bergeben wird.*/
Thread t = new Thread(meinFaden);
/*Der so erstellte Thread wird gestartet.*/
t.start();
}
/*Die Methode run() muss berschrieben werden.*/
public void run() {
System.out.println("Ich bin der Thread MeinFaden");
}
}
Listing 8.1: MeinFaden.java

Ausgabe:
Ich bin der Thread MeinFaden
Der Thread wird gestartet mit der Methode start(). Diese fhrt zuerst die Methode start() aus
und anschlieend die Methode run(). Ein Thread kann nur einmal mit der Methode start()
gestartet werden. Wenden Sie die Methode run() an, wird nur die Methode run() durchgefhrt
und kein Thread gestartet.

8.1.2 Mithilfe der Klasse Thread


Erstellen Sie einen neuen Thread mithilfe einer Vererbungsbeziehung zu der Klasse Thread,
mssen Sie nicht die Methode run() implementieren, sie drfen sie aber berschreiben.
Unser nchster Thread heit ZweiterThread.java und er gibt nachfolgenden Satz auf der Konsole
aus:

1
2
3
4
5
6
7
8
9
10
11
12

package Kap08;
public class ZweiterThread extends Thread{

134

public static void main(String[] args){


/*Der Thread wird instanziiert und*/
ZweiterThread zweiterThread = new ZweiterThread();
/*anschlieend gestartet.*/
zweiterThread.start();

8.2 Synchronisation

13
14
15
16
17
18
19
20
21

}
/*Die Methode run() der Klasse Thread darf berschrieben
werden, sie muss es aber nicht.*/
public void run() {
System.out.println("Ich bin der Thread ZweiterThread");
}
}
Listing 8.2: ZweiterThread.java

Ausgabe:
Ich bin der Thread ZweiterThread

8.2 Synchronisation
Was verstehen wir unter Synchronisation? Synchronisation stellt sicher, dass Vorgnge hintereinander und nicht gleichzeitig und durcheinander ablaufen. Werden Prozesse synchronisiert, so
nennt man diesen Zustand threadsafe oder in der deutschen bersetzung threadsicher.

8.2.1 Synchronisierte Blcke


Wie synchronisiere ich einen Thread? Eine Mglichkeit ist es, einen ganzen Codeblock zu synchronisieren. Lassen Sie uns zuerst das Verhalten von Threads betrachten, die nicht synchronisiert
sind. Dies lsst sich anhand eines einfachen Beispiels demonstrieren: Wir erstellen in der forSchleife des unten stehenden Threads mit Namen NichtSynchro.java die zweimalige Ausgabe der
Zahlen von 1  199. Die beiden Threads laufen nicht hintereinander ab, sondern in willkrlicher
plattformabhngiger Reihenfolge, wie die Ausgabe zeigt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

package Kap08;
public class NichtSynchro extends Thread{
public static void main(String[] args){
NichtSynchro nichtSynchro = new NichtSynchro();
NichtSynchro nichtSynchro2 = new NichtSynchro();
nichtSynchro.start();
nichtSynchro2.start();
}
public void run(){

135

8 Exkurs: Threads und Multithreading

for(int i=0; i<200;i++){


System.out.println(i);
}

17
18
19
20
21
22

}
}
Listing 8.3: NichtSynchro.java

Ausgabe (Ausschnitt):
124
0
125
1
126
2
127
3
Wollen Sie, dass diese beiden Threads hintereinander ablaufen, bentigen Sie ein sogenanntes
LOCK: das
private

static

O b j e c t LOCK =

new

Objekt ( ) ;

Statische Bestandteile einer Klasse gibt es nur ein einziges Mal pro Klasse, wohingegen jeder
nicht statische Bestandteile einer Klasse, pro Objekt existiert. So wird ein statisches LOCK, da
es pro Klasse nur einmal existiert, von allen Objekten dieser Klasse geteilt. Alle Objekte der
Klasse haben also nur ein einziges LOCK, das sie sich teilen mssen. So kann auch immer nur ein
Objekt auf dieses LOCK zugreifen. Statische Variablen werden deshalb auch Klassenvariablen
genannt und nicht-statische Variablen Instanzvariablen, da es sie pro Instanz, also pro Objekt,
einmal gibt.
Im folgenden Thread mit Namen Synchro.java stellen wir sicher, dass jeweils immer nur ein
Thread den Block ausfhren darf, in dem sich die for-Schleife bendet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

package Kap08;
public class Synchro extends Thread{

136

private static Object LOCK = new Object();


public static void main(String[] args){
Synchro synchro = new Synchro();
Synchro synchro2 = new Synchro();
synchro.start();
synchro2.start();

8.2 Synchronisation

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

}
public void run(){
/*Wir synchronisieren den Ablauf der for-Schleife
mithilfe eines statischen LOCKs.*/
synchronized(LOCK){
for(int i=0; i<200;i++){
System.out.println(i);
}
}
}
}
Listing 8.4: Synchro.java

Ausgabe (Ausschnitt):
196
197
198
199
0
1
2
3
Wie die Ausgabe zeigt, funktioniert das Locken von Blcken ohne Probleme. Die Threads werden
hintereinander abgearbeitet und es kommt zu einer Ausgabe von 1  199 zweimal hintereinander.
Was aber wrde passieren, wenn Sie das LOCK durch this ersetzen? Es kommt wieder zu einer
nicht synchronisierten Ausgabe der Zahlen, da sich this auf das jeweilige Objekt bezieht und
nicht auf die Klasse. So besitzt jedes Objekt seine eigene Methode run() und jedes Objekt kann
problemlos darauf zugreifen. Es gibt also keinen gelockten Bereich.
Folgender Thread ThisSynchro.java und die dazugehrige Ausgabe zeigt, dass die for-Schleife
nicht hintereinander auaufen:

1
2
3
4
5
6
7
8
9
10

package Kap08;
public class ThisSynchro extends Thread{
public static void main(String[] args){
ThisSynchro thisSynchro = new ThisSynchro();
ThisSynchro thisSynchro2 = new ThisSynchro();
thisSynchro.start();

137

8 Exkurs: Threads und Multithreading

thisSynchro2.start();

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

}
public void run(){
synchronized(this){
for(int i=0; i<200;i++){
System.out.println(i);
}
}
}
}
Listing 8.5: ThisSynchro.java

Ausgabe (Ausschnitt):
124
0
125
1
126
2
127
3
Wie werden in db4o Datenbankabfragen synchronisiert? Mithilfe von Semaphores. Semaphores
werden ausfhrlich im Kapitel Transaktionen besprochen.

138

9 Client-Server-Modus
Bis jetzt haben wir db4o im Solo-Modus benutzt. Was aber machen Sie, wenn Sie db4o in
einem Netzwerk oder im Internet verwenden wollen? Dann haben Sie mindestens einen Client
und einen Server. Der Server luft und wartet auf Anfragen von verschiedenen Benutzern, den
Clients, und arbeitet diese Anfragen ab. Der Benutzer fragt Daten ab oder gibt sie ein, und der
Server bearbeitet sie. Es gibt drei verschiedene Arten von Client-Server-Beziehungen, die von
db4o untersttzt werden:

1.

Netzwerkmodus: Der Client und der Server interagieren in einem Netzwerk via TCP/IP
miteinander. Dieser Modus wird z. B. bentigt, wenn der Datenbankserver und der Client
sich nicht innerhalb der gleichen Virtual Machine benden.

2.

Embedded-Modus: Es ndet eine Interaktion von Client und Server innerhalb einer Virtual Machine statt und der Client und Server bendet sich in einer Einheit. Dieser Modus
eignet sich besonders fr PDAs oder Industrieroboter. Der Embedded Modus eignet sich
auch hervorragend fr unser Webprojekt, da sich das gesamte Projekt normalerweise auf
einem Server mit einem Webcontainer, wie z. B. Tomcat, bendet. So nden alle Serverund Clientaktionen auf einem Webcontainer statt, da es sich bei den Clients nur um virtuelle Clients handelt. Alle Abfragen eines Webprojektes werden innerhalb einer Virtual
Machine durchgefhrt und an die Benutzer werden nur fertige HTML-Seiten gesendet. Der
Embedded-Modus hat auerdem den Vorteil gegenber dem Client-Server-Modus schneller
zu sein, da hier keine Verluste durch das Versenden von Daten mit dem TCP/IP-Protokoll
stattnden. In diesem Modus kann der db4o interne Cache verwendet werden, der es erlaubt mit Objekten zu arbeiten, die sich im Arbeitsspeicher benden. So kann die Anzahl
der tatschlichen Anfragen reduziert werden und es knnen mehr Personen gleichzeitig auf
die Datenbank zugreifen.

3.

Out-of-Band-Signalling: Clients knnen dem Server Nachrichten senden. Wichtige Anwendungsflle fr das Out-of-Band-Signalling sind: Sie knnen den Server stoppen oder
den Befehl erteilen, die Defragmentation zu starten.

Wie Sie sehen, haben wir die Welt des Solo-Modus verlassen und bewegen uns jetzt in einer
komplexeren Welt, in der Welt des Client-Server-Modus und der Embedded Modus-Interaktion.
Der Embedded-Modus stellt die Basis fr die Datenbankabfragen in unserem Webprojekt dar.

9.1 Netzwerkmodus
Im Netzwerkmodus bentigen wir einen Client und einen Server, die jeweils in einem Thread
gestartet werden. Beginnen wir mit dem Server: Der Server wird mit der Methode openServer()
genet. Die Methode openServer() wirft eine DataBaseFileLockedException und Sie bergeben

139

9 Client-Server-Modus

ihr zwei Parameter. Der erste Parameter ist der Pfad zu Ihrer Datenbank, die genet werden
soll, und der zweite Parameter ist ein TCP/IP-Port, der nicht vergeben sein sollte.
Auerdem brauchen Sie eine Verbindung vom Server zum Client: Der Client kommuniziert mit
dem Server, indem der Server dem Client Zutritt mit der Methode grantAccess() gewhrt. Der
Methode werden zwei Parameter bergeben, wobei der erste der Namen des Client ist und der
zweite ein Passwort, das Sie beliebig vergeben knnen.
Unten stehender Thread net unseren Server, der gleich nach dem Start mithilfe der Methode
wait() in einen Wartezustand bergeht, sprich er wartet auf Clients, die mit ihm in Interaktion
treten. Die Methode wait() ist eine Methode der Klasse Object, die eine InterruptedException
wirft, die aufgefangen werden muss, deshalb muss die Methode wait() in einem try-catch-Block
stehen. Auerdem muss sie sich in einem synchronized-Block benden.
Eigentlich mssten sowohl die DatabaseFileLockedException als auch die InterruptedException
jeweils in einem separaten catch-Block aufgefangen werden, der bersichtlichkeit halber habe
ich darauf verzichtet. So fange ich jetzt beide Exceptions mit nur einem catch-Block auf, der
alle Exceptions aungt. Wie wir den Server wieder schlieen, werden wir in dem Kapitel zum
Thema Out-of-Band-Signalling lernen.
Hier die Klasse Server.java, die in einem Thread einen Server mit der Methode openServer()
net:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

package Kap09;
import com.db4o.Db4o;
import com.db4o.ObjectServer;
public class Server extends Thread {

140

public static void main(String[] args){


Server s = new Server();
s.start();
}
public void run() {
synchronized(this){
ObjectServer server = Db4o.openServer
("C:/Datenbank/DasErsteProjekt/datenbank.yap", 8080);
server.grantAccess("user1", "password");
try{
System.out.println("Server");
this.wait();
} catch(Exception e){
e.printStackTrace();
} finally{
System.out.println("aus");

9.1 Netzwerkmodus

30
31
32
33
34

server.close();
}
}
}
}
Listing 9.1: Server.java

Sollte noch eine Datenbank vorhanden sein, lschen Sie diese, da wir jetzt eine neue mit neuem
Inhalt erstellen wollen. Starten wir nun unseren Thread, in dem der Server genet wird, mit
Shift + F6, knnen wir in NetBeans gut sehen, wie unser Server luft und luft..........

Abbildung 9.1: Server wartet auf den Client, der mit ihm in Interaktion treten wird
Als Nchstes brauchen wir einen Client: Einen Client nen wir mit der Methode openClient().
Der Methode openClient() mssen Sie als Parameter zuerst localhost, die Portnummer, den
Namen des Client und anschlieend das Passwort bergeben. Die Methode openClient() wirft
eine IOException, die Sie im catch-Block auangen mssen.
Unten stehender Thread mit Namen Client.java net einen Client, der einen Link mit Namen
"Home" in der Datenbank speichert .

1
2
3
4
5
6
7
8
9
10
11

package Kap09;
import
import
import
import

Datenbankentwurf.Link;
com.db4o.Db4o;
com.db4o.ObjectContainer;
java.io.IOException;

public class Client extends Thread{


ObjectContainer client = null;

141

9 Client-Server-Modus

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

public static void main(String[] args){


Client c = new Client();
c.start();
}
public void run() {
try{
client = Db4o.openClient
("localhost", 8080, "user1", "password");
System.out.println("Client");
Link l = new Link("Home");
client.set(l);

}
}

} catch(IOException e){
e.printStackTrace();
} finally{
System.out.println("Client aus");
client.close();
}

Listing 9.2: Client.java


Starten wir den Client, wird ein zweiter Thread gestartet und wieder beendet, wobei der Thread
des Servers weiterluft. Der Server bleibt also immer genet, solange bis ihn eine Nachricht
erreicht, er solle aufhren zu laufen.

Abbildung 9.2: Client tritt in Kommunikation mit dem Server


In einem zustzlichen Thread nen wir einen weiteren Client und lesen den soeben gespeicherten
Link mit Namen "Home" wieder aus.

142

9.1 Netzwerkmodus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

package Kap09;
import
import
import
import
import

Datenbankentwurf.Link;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
java.io.IOException;

public class ClientAus extends Thread{


ObjectContainer client = null;
public static void main(String[] args){
ClientAus c = new ClientAus();
c.start();
}
public void run() {
try{
client = Db4o.openClient
("localhost", 8080, "user1", "password");
System.out.println("Client");
Link l = new Link(null);
ObjectSet<Link> result = client.get(l);
while(result.hasNext()){
l = result.next();
System.out.println(l.getName());
}
} catch(IOException e){
e.printStackTrace();
} finally{
System.out.println("Client aus");
client.close();
}
}
}
Listing 9.3: ClientAus.java

Wir erhalten das gewnschte Ergebnis und folgende Ausgabe:


Client
Home
Client aus

143

9 Client-Server-Modus

Wir haben gesehen: Der Server wird gestartet und wartet stndig auf Anfragen der Clients. Die
Clients fragen beim Server an, und sie speichern dann anschlieend Daten oder lesen sie aus.

9.2 Embedded-Modus
Der Embedded-Modus luft auf einer Virtual Machine, sprich auf einem einzigen Gert, wie
z. B. einem Handy. Oder: Auf einem Webcontainer, wie z. B. Tomcat. Wir werden im Kapitel
Embedded-Modus in einem Web-Projekt sehen, wie der Embedded-Modus in unser ContentManagement-System integriert werden kann.
Beginnen wir hier an dieser Stelle mit der allgemeinen Funktionsweise des Embedded Modus:
Genau wie im Netzwerkmodus mssen Sie den Server mit der Methode openServer() nen.
Im Embedded Modus mssen Sie ihr aber nur zwei Parameter bergeben, und zwar den Pfad
der Datenbank und den Port. Im Embedded-Modus wird der Port 0 vergeben, da dieser keine
bestimmte Aufgabe hat. Der Client wird mit openClient() genet und ihr wird kein Parameter
bergeben.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

package Kap09;
import
import
import
import
import

Datenbankentwurf.Link;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectServer;
com.db4o.ObjectSet;

public class EmbeddedServer extends Thread {

144

public static void main(String[] args){


EmbeddedServer s = new EmbeddedServer();
s.start();
}
public void run() {
ObjectContainer client = null;
ObjectServer server = Db4o.openServer
("C:/Datenbank/DasErsteProjekt/datenbank.yap", 0);
try{
System.out.println("Embedded Server");
client = server.openClient();
System.out.println("Embedded Client");
Link l = new Link("Home");
client.set(l);
} catch(Exception e){
e.printStackTrace();
} finally{
System.out.println("aus");

9.3 Out-of-Band-Signalling

34
35
36
37

server.close();
}
}
}
Listing 9.4: EmbeddedServer.java

Die Daten werden gespeichert und wir erhalten folgende Ausgabe:


Embedded Server
Embedded Client
aus

9.3 Out-of-Band-Signalling
Wie stoppen wir den Server wieder? Der Client schickt dem Server eine Nachricht. Werden Nachrichten vom Client an den Server gesendet, wird dieser Vorgang in db4o Out-of-Band-Signalling
genannt. Der Client ist der Sender der Nachricht und der Server ist der Empfnger. Der Nachrichtenempfnger heit in db4o MessageRecipient und der Nachrichtensender MessageSender.
Die entsprechenden Interfaces nden Sie in der db4o-API im Package com.db4o.messaging:

Abbildung 9.3: Das Package com.db4o.messaging


Wie werden Nachrichten in unserer Client-Server-Umgebung integriert? Lassen Sie uns mit dem
Server beginnen: Der Server muss das Interface MessageRecipient und dessen Methode processMessage() implementieren. In dieser Methode wird die Methode notify() auf dem Server mit
Namen serverO ausgefhrt. Die Methode notify() ist eine Methode der Klasse java.lang.Object
und sie benachrichtigt den Server serverO, dass er aufhren soll zu warten. Die Objektreferenz
this im synchronized-Block stellt in diesem Zusammenhang sicher, dass notify() auch den wartenden Server aufweckt, ohne this passiert dies nicht. Mit this wird gewhrleistet, dass auf den
Server serverO Bezug genommen wird.
In der Klasse ServerO.java nden Sie das vollstndige Listing:

1
2
3
4
5
6

package Kap09;
import
import
import
import

com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectServer;
com.db4o.messaging.MessageRecipient;

145

9 Client-Server-Modus

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

public class ServerOff extends Thread implements MessageRecipient{

146

public static void main(String[] args){


ServerOff serverOff = new ServerOff();
serverOff.start();
}
public void processMessage
(ObjectContainer objectContainer, Object message){
/*Die Methode notify() muss in einem synchronisierten
Block stehen und this bezieht sich auf das Objekt serverOff,
das in der oben stehenden main instanziiert wurde. Es bezieht
sich also auf den Thread selbst, in dem sich der Server
befindet.*/
synchronized(this){
/*Der Operator instanceof stellt fest, ob es sich bei
der Nachricht, um ein StopServer-Objekt handelt.*/
if(message instanceof StopServer){
/*Handelt es sich um ein StopServer-Objekt, wird das
Objekt serverOff benachrichtigt, er solle aufhren zu
laufen.*/
this.notify();
}
}
}
public void run() {
synchronized(this){
ObjectServer server = Db4o.openServer
("C:/Datenbank/DasErsteProjekt/datenbank.yap", 8080);
server.grantAccess("user1", "password");
/*Der Thread, indem sich der Server befindet, wird als
Nachrichtenempfnger festgelegt.*/
server.ext().configure().clientServer().setMessageRecipient(this);
try{
System.out.println("Server luft und soll gestoppt werden");
this.wait();
} catch(Exception e){
e.printStackTrace();

9.3 Out-of-Band-Signalling

56
57
58
59
60
61
62

} finally{
System.out.println("aus");
server.close();
}
}
}
}
Listing 9.5: ServerO.java

Wir starten unseren Thread ServerO.java mit Shift + F6 und erhalten folgende Ausgabe:

Abbildung 9.4: Der Server wird gestartet


Jetzt fehlt nur noch der Client, der unseren Server stoppt: Sie senden mit der Methode send() des
Interfaces MessageSender eine Nachricht an den Server. Dies tun Sie mithilfe eines StopServerObjektes, das Sie weiter unten nden. In unten stehendem Thread StopClient.java nden Sie das
entsprechende Listing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package Kap09;
import
import
import
import

com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.messaging.MessageSender;
java.io.IOException;

public class StopClient extends Thread {


ObjectContainer client = null;
public static void main(String[] args){
StopClient stopClient = new StopClient();
stopClient.start();
}
public void run() {
try{
client = Db4o.openClient
("localhost", 8080, "user1", "password");
System.out.println("Client sagt Stop");

147

9 Client-Server-Modus

} catch(IOException e){
e.printStackTrace();
} finally{

24
25
26
27
28
29
30
31
32
33
34
35
36

MessageSender messageSender =
client.ext().configure().clientServer().getMessageSender();
messageSender.send(new StopServer());

}
}

System.out.println("Client aus");
client.close();
}

Listing 9.6: StopClient.java


Was ist ein StopServer-Objekt? Ein einfaches Objekt, das keinen Inhalt haben muss, sondern
nur im Server zur Identizierung der Nachricht dient.

1
2
3
4
5
6
7
8

package Kap09;
public class StopServer {
public StopServer() {
}
}

Listing 9.7: StopServer.java


Starten wir den Thread StopClient.java wird tatschlich, wie Sie unten sehen knnen, der Server
gestoppt:

Abbildung 9.5: Der Server wird gestoppt

Und auerdem luft der Thread StopClient.java und endet mit folgender Ausgabe auf der Konsole:

148

9.3 Out-of-Band-Signalling

Abbildung 9.6: Der Thread des Clients wird vollstndig abgearbeitet

149

10 Transaktionen

10.1 Grundlagen
Was sind Transaktionen? Transaktionen sind mehrere Datenbankoperationen, die logisch zusammengehren. Bei Transaktionen werden mehrere Speicher- oder Lschvorgnge zu einem Schritt
zusammengefasst und als Einheit betrachtet und ausgefhrt. In db4o wird immer mit Transaktionen gearbeitet, auch wenn es sich nur um einen einzigen Arbeitsschritt handelt. Eine Transaktion
beginnt in db4o mit der Methode openFile() und endet mit close().
Sollte es zu einem Abbruch whrend einer Transaktion kommen, knnen alle Operationen mit der
Methode rollback() wieder rckgngig gemacht werden. Grnde fr einen Abbruch knnen sein:
Stromausfall, Abbruch durch den Benutzer, Arbeitsspeicherprobleme, Netzwerkprobleme und
Softwarefehler. Die Methode commit() stellt sicher, dass alle Speichervorgnge in die Datenbank
geschrieben werden und somit fr Transaktionen durch andere Personen sichtbar werden. Sie
beendet aber nicht die Transaktion. Die Methode close() beendet die Transaktion und schreibt
nicht nur Daten in die Datenbank, sondern schliet sie auch.
Lassen Sie uns diesen Vorgang anhand des Lschvorgangs eines WebSite-Objektes demonstrieren.
Zuvor lschen wir eine eventuell vorhandene Datenbank und erstellen mit unten stehender Klasse
eine Neue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

package Kap10;
import
import
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Kap05.FormatierungSpeichern;
Kap06.WebSiteEin;
java.util.ArrayList;

public class FormatierungWebSite {


public static void main(String[] args){
FormatierungSpeichern fd = new FormatierungSpeichern();
Formatierung f = new Formatierung("font1");
Formatierung form = new Formatierung("font2");
fd.speichern(f);
fd.speichern(form);
Link link = new Link("Home");
Text t = new Text("Erster Text");

151

10 Transaktionen

Text te = new Text("Zweiter Text");


ArrayList<Text> at = new ArrayList<Text>();
at.add(t);
at.add(te);

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

Formatierung fo = new Formatierung("font1", at);


ArrayList<Formatierung> af = new ArrayList<Formatierung>();
af.add(fo);
Bild b = new Bild("BildHome", "Bilder/home.jpg");
Bild bZwei = new Bild("BildHomeZwei", "Bilder/homeZwei.jpg");
ArrayList<Bild> ab = new ArrayList<Bild>();
ab.add(b);
ab.add(bZwei);
PDF p = new PDF("PDFHome", "Dokumente/home.pdf");
PDF pZwei = new PDF("PDFHomeZwei", "DokumenteZwei/home.pdf");
ArrayList<PDF> ap = new ArrayList<PDF>();
ap.add(p);
ap.add(pZwei);
String reihenfolge = new String("1");
String ebene = new String("");
WebSiteEin w = new WebSiteEin();
w.addWebSite(link, af, ab, ap, reihenfolge, ebene);
}
}
Listing 10.1: FormatierungWebSite.java
Als Nchstes erstellen wir eine Klasse, die die Daten einzeln ausliest, sprich jedes Objekt fr sich,
um spter nach dem Lschen vergleichen zu knnen, ob nicht nur das Objekt der Klasse WebSite
gelscht wurde, sondern alle anderen auch. Zu diesem Zweck greifen wir in der Klasse FormatierungWebSiteAus.java auf Methoden und Klassen zurck, die wir bereits in den vorangegangenen
Kapiteln erstellt haben.

1
2
3
4
5
6
7
8
9
10
11
12

package Kap10;
import
import
import
import
import
import
import
import
import
import

152

Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
Datenbankentwurf.Verlinkung;
Kap05.ArrayListAuslesen;
Kap05.ArrayListAuslesenAusDatenbank;
Kap05.FormatierungAuslesen;
Kap05.FormatierungTextAusDatenbank;
Kap05.TextOhneFormatierungAusDatenbank;
Kap05.TextOhneFormatierungAuslesen;

10.1 Grundlagen

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

import
import
import
import

Kap05.VerlinkungAusDatenbank;
Kap05.VerlinkungAuslesen;
Kap05.BildAuslesen;
java.util.ArrayList;

public class FormatierungWebSiteAus {


public static void main(String[] args){
/* FormatierungAuslesen fau = new FormatierungAuslesen();
ArrayList<Formatierung> al = fau.auslesen();
for(Formatierung f : al){
System.out.println("Formatierung: "+ f.getName());
ArrayList<Text> at = f.getText();
System.out.println("Elemente in der ArrayList: " + at.size());
for(Text t : at){
System.out.println("Text zu Formatierung: "+ t.getName());
}
}*/
TextOhneFormatierungAuslesen to = new TextOhneFormatierungAuslesen();
ArrayList<Text> at = to.auslesen();
for(Text t: at){
System.out.println("Name des Textes: "+t.getName());
}
VerlinkungAuslesen va = new VerlinkungAuslesen();
ArrayList<Verlinkung> av = va.auslesen();
for(Verlinkung v : av){
System.out.println("Pdf- oder Linkname: "+v.getName() );
}
BildAuslesen ba = new BildAuslesen();
ArrayList<Bild> b = ba.auslesen();
for(Bild bi: b){
System.out.println("Name des Bildes: "+bi.getName());
System.out.println("Pfad des Bildes: "+bi.getPfad());
}
ArrayListAuslesen ala = new ArrayListAuslesen();
ArrayList<ArrayList> alist = ala.auslesen();
for(ArrayList a : alist){
System.out.println("Gre: "+a.size());
}
}
}
Listing 10.2: FormatierungWebSiteAus.java

153

10 Transaktionen

Ausgabe:
Formatierung: font1
Elemente in der ArrayList: 2
Text zu Formatierung: Erster Text
Text zu Formatierung: Zweiter Text
Formatierung: font2
Elemente in der ArrayList: 0
Name des Textes: Erster Text
Name des Textes: Zweiter Text
Pdf- oder Linkname: Home
Pdf- oder Linkname: PDFHome
Name des Bildes: BildHome
Pfad des Bildes: Bilder/home.jpg
Gre: 0
Gre: 2
Gre: 2
Gre: 1
Gre: 1
Jetzt kommen wir zu dem eigentlichen Lschvorgang: Mit unten stehender Methode deleteWebSite() der Klasse WebSiteLoeschen.java lschen wir ein Objekt der Klasse WebSite, wobei die
Methode rollback() im catch-Block steht, fr den Fall, dass es zu Problemen beim Lschen kommen sollte. In diesem Fall werden alle Befehle des try-Blocks wieder rckgngig gemacht. Der
Lschvorgang besteht aus mehreren Vorgngen, die zu einer Transaktion zusammengefasst werden:
1. Sie mssen das WebSite-Objekt lschen.
2. Sie mssen auch alle darin enthaltenen Objekte der Klassen Bild, PDF und Text lschen.
3. Sie mssen die jetzt leeren ArrayListen separat lschen.
4. Die gelschten Objekte der Klasse Text mssen auch aus der ArrayList des entsprechenden
Formatierungsobjektes entfernt werden.
In diesem Fall ist es sinnvoll, wirklich alle Daten zu lschen, die sich in dem Objekt WebSite
benden. Aber Vorsicht: Wollen Sie z.B. eine Rechnung aus der Datenbank entfernen, drfen Sie
nicht die dazugehrigen Artikel- und Kundendaten lschen, sondern nur die Rechnung selbst.

1
2
3
4
5
6
7
8
9
10

package Kap10;
import
import
import
import
import
import
import
import

154

Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;

10.1 Grundlagen

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

import
import
import
import

com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Predicate;
java.util.ArrayList;

public class WebSiteLoeschen {


public void deleteWebSite(Link link){
/*Die Methode cascadeOnUpdate(true) ermglicht es Ihnen,
die Objekte der Klasse Text aus der ArrayList<Text>
der Formatierungsobjekte zu lschen.*/
Db4o.configure().objectClass(Formatierung.class).
cascadeOnUpdate(true);
/*Es werden alle Objekte in dem entsprechenden Objekt
der Klasse WebSite gelscht. */
Db4o.configure().objectClass(WebSite.class).
cascadeOnDelete(true);
ObjectContainer db = Db4o.openFile
("C:/Datenbank/DasErsteProjekt/datenbank.yap");
Formatierung form = new Formatierung();
try {
WebSite w = new WebSite(link, null, null, null, null, null);
ObjectSet<WebSite> resultWebSite = db.get(w);
w = resultWebSite.next();
/*Zuerst werden alle Bildobjekte einzeln gelscht,*/
ArrayList<Bild> bild = w.getBild();
for(Bild b: bild){
db.delete(b);
}
/*anschlieend wird die ArrayList<Bild> gelscht.*/
db.delete(bild);
/*Die PDF-Objekte werden einzeln gelscht,*/
ArrayList<PDF> pdf = w.getPdf();
for(PDF p: pdf){
db.delete(p);
}
/*dann wird die ArrayList<PDF> gelscht.*/
db.delete(pdf);

155

10 Transaktionen

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

156

ArrayList<Text> text = w.getText();


/*Die ArrayList<Text> des WebSite-Objektes wird ausgelesen,*/
for(Text te: text){
/*die darin enthaltenen Textobjekte mssen zuerst aus der
Datenbank ausgelesen werden, da sie sonst nicht aus
der ArrayList<Text> der Formatierungsobjekte gelscht
werden knnen. Und sie mssen wieder einer neuen
ArrayList<Text> listText hinzugefgt werden.*/
ObjectSet<Text> resultText = db.get(te);
while (resultText.hasNext()){
Text t = resultText.next();
ArrayList<Text> listText = new ArrayList<Text>();
listText.add(t);
/*Das Formatierungsobjekt zu dem der Text gehrt,
wird aus der Datenbank ausgelesen, indem dem Beispielobjekt die soeben erstellte ArrayList<Text> listText
als Parameter bergeben wird.*/
Formatierung fo = new Formatierung(null, listText);
ObjectSet<Formatierung> resultFormat = db.get(fo);
while (resultFormat.hasNext()){
Formatierung forme = resultFormat.next();
ArrayList<Text> formatText = forme.getText();
/*Der Text, der zur WebSite gehrt, wird aus
der ArrayList<Text> des Formatierungsobjektes
gelscht.*/
formatText.remove(t);
/*Die genderte ArrayList<Text> wird wieder dem Formatierungsobjekt
zugewiesen,*/
forme.setText(formatText);
/*Danach wird wieder das Formatierungsobjekt gespeichert.*/
db.set(forme);
}
}
}
/*Anschlieend werden alle Textobjekte aus der ArrayList<Text>
des WebSite-Objektes einzeln gelscht,*/
for(Text t: text){
db.delete(t);
}
/*und zum Schluss wird die ArrayList<Text> gelscht.*/

10.1 Grundlagen

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

db.delete(text);
/*Das Objekt WebSite wird gelscht.*/
db.delete(w);
} catch (DatabaseFileLockedException e) {

/*Sollte es zu Problemen beim Lschen des WebSite-Objektes


kommen, werden alle oben stehenden Vorgnge wieder rckgngig
gemacht.*/
db.rollback();
} finally{
db.commit();
db.close();
}
}

Listing 10.3: WebSiteLoeschen.java


Wir lschen die WebSite, die einen Link mit Namen "Home" besitzt mit der folgenden Klasse:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

package Kap10;
import Datenbankentwurf.Link;
public class WebSiteLoeschenAusDatenbank {
public static void main(String[] args){
WebSiteLoeschen wsl = new WebSiteLoeschen();
Link l = new Link("Home");
wsl.deleteWebSite(l);
}
}
Listing 10.4: WebSiteLoeschenAusDatenbank.java

Wir lesen die Daten mithilfe der Klasse FormatierungWebSiteAus.java aus, um festzustellen, ob
tatschlich alles gelscht wurde:
Formatierung: font1
Elemente in der ArrayList: 0
Formatierung: font2
Elemente in der ArrayList: 0
Gre: 0

157

10 Transaktionen

Gre: 0
Und tatschlich es wurde das Objekt der Klasse WebSite gelscht und alle darin enthaltenen
Objekte. Es sind nur die zwei Formatierungsobjekte und die darin enthaltenen Listen brig
geblieben. Sie knnen sich sicherlich vorstellen, welche Probleme auftauchen knnen, wenn nicht
alle Schritte innerhalb der Transaktion durchgefhrt oder wieder rckgngig gemacht werden. So
knnte es passieren, dass Texte weiterhin den Formatierungsobjekten zugeordnet, aber tatschlich
aus der Datenbank gelscht worden sind, was zu einer NullPointerException fhren wrde. Dieses
Problem wird umgangen, indem alle Anweisungen, die ein Objekt der Klasse WebSite und die
darin enthaltenen Objekte lscht, entweder ganz oder gar nicht durchgefhrt werden.

10.1.1 Transaktionen und die Methode refresh()


Wozu brauche ich bei Transaktionen die Methode refresh()? Um Daten nach einem Rollback
aktualisieren zu knnen. In dem obigen Beispiel fr Transaktionen ist dies nicht notwendig, da
die Datenbank nach jedem Lschvorgang wieder geschlossen wird. Sollte aber im Embedded
Modus die Datenbank whrend eines lngeren Zeitraums genet bleiben, mssen die Daten
der Datenbank nach einem Rollback wieder auf den neuesten Stand gebracht werden, da der
Arbeitsspeicher von db4o nicht automatisch aktualisiert wird (siehe Kapitel Embedded Modus
in einem Web-Projekt . So knnte es sein, dass Sie nach einem Rollback mit Daten aus dem
Arbeitsspeicher weiterarbeiten. Die entsprechende Befehlszeile ist die Folgende:
db . e x t ( ) . r e f r e s h (w ,

I n t e g e r .MAX_VALUE) ;

Der Methode refresh() werden 2 Parameter bergeben: Ein Objekt der entsprechenden Klasse,
hier das Objekt der Klasse WebSite mit Namen w, und die Suchtiefe. Die Methode refresh()
bendet sich im Interface ExtObjectContainer im Package com.db4o.ext.

10.2 ACID
Leider kann ich Ihnen ein klein wenig Theorie zu den Transaktionen nicht ersparen, da dies
unerlsslich fr das tiefer gehende Verstndnis der Zusammenhnge ist. Transaktionen werden
anhand der so genannten ACID-Kriterien beschrieben und gemessen. Was versteht man unter
der Abkrzung ACID? ACID ist die Abkrzung fr die Begrie Atomicity, Consistency, Isolation
und Durability. Was aber verbirgt sich hinter diesen Fachbegrien?
1.

Atomicity:

Mehrere Operationen knnen als Einzige aufgefasst werden, und damit als

Ganzes ausgefhrt oder rckgngig gemacht werden.


2.

Consistency: Daten vor und nach der Transaktion mssen widerspruchsfrei sein. Liefern
Sie z.B. 2 Bcher aus, so muss auch der Bcherbestand um 2 Bcher abnehmen.

3.

Isolation: Gleichzeitig ablaufende Transaktionen drfen sich nicht gegenseitig beeinussen.

4.

Durability: Speichervorgnge, die vom Benutzer besttigt worden sind, drfen nicht verloren gehen.

Atomicity und Durability werden in der Datenbank db4o sichergestellt. In den Transaktionen
spiegelt sich die Atomicity wieder, da mehrere Datenbankvorgnge zu einem zusammengefasst
werden knnen. Und fr die Durability wurden spezielle Mechanismen, wie z.B. die Replikation,
entwickelt.

158

10.2 ACID

Wie sieht es aber mit der Consistency und der Isolation aus? Insbesondere die Isolation spielt bei
Transaktionen eine groe Rolle. So knnen, verschiedene Isolationsstufen deniert und gestaltet
werden. Dies werden wir im nchsten Abschnitt sehen.

10.2.1 Isolationsstufen
Oben steht, gleichzeitig ablaufende Transaktionen drfen sich nicht gegenseitig beeinussen. Was
aber passiert, wenn 2 Kunden gleichzeitig das gleiche Buch bestellen wollen? Und es gibt nur noch
eines auf Lager und Sie wollen verhindern, dass dieses Buch beide erhalten? Es gibt verschiedene
so genannte Isolationsstufen, die versuchen dieses Problem zu lsen:

1.

Serializable: Transaktionen laufen hintereinander ab, so knnen sie sich nicht gegenseitig
beeinussen, und es geht keine Transaktion verloren. Dies setzt voraus, dass auf bestimmte
Transaktionen nur ein Benutzer zugreifen kann. Transaktionen werden also gelockt, was
auf Kosten der Performance gehen kann.

2.

Repeatable Read: Normalerweise erhalten Sie whrend einer Transaktion, die lesenden
Zugri auf die Datenbank hat, immer das gleiche Ergebnis, wenn Sie diesen Zugri whrend
der Transaktion wiederholen. Bei Repeatable Read besteht allerdings die Mglichkeit von
so genannten Phantom Reads, bei denen eine Transaktion Daten ausliest, und das Ergebnis
wenig spter einen zustzlichen Datensatz enthlt, da im Verlaufe der Transaktion durch
eine andere Transaktion, ein Datensatz hinzugefgt wurde.

3.

Read Committed: Genderte Daten innerhalb einer Transaktion werden fr andere nach
einem commit sofort sichtbar. Hierdurch kann die Situation entstehen, dass die Daten, auf
die in einer Transaktion zugegrien werden soll, am Anfang einer Transaktion andere sind
wie am Ende einer Transaktion.

4.

Read Uncommitted: Bei dieser Isolationsstufe sind alle Daten einer Transaktion sofort
fr alle anderen Transaktionen - auch ohne commit - sichtbar.

Diese vier Stufen entsprechen im Falle von Serializable einer extrem pessimistischen Sicht der
Speicherablufe, die dann von einer Stufe zur nchsten auf eine immer positivere Sicht bergeht.
So geht Read Uncommited davon aus, dass es keine Transaktionen gibt, die sich wechselseitig
beeinussen. Dies ist sicherlich nur bei Einzelplatzanwendungen eine sinnvolle Annahme.
Das Locken von Transaktionen, das analog zu synchronisierten Blcken in Java funktioniert, ist
sicherlich bei sensiblen Daten, wie z.B. bei Ein- und Auszahlungen auf Bankkonten unbedingt
notwendig. Es geht aber mit eventuellen Einbuen bei der Performance einher.
In unten stehendem Unterkapitel zum Thema Semaphores werden wir sehen, dass das Locken
von bestimmten Objekten nur einen begrenzt negativen Einuss auf die Performance hat. Es
muss aber oft - je nach Erfordernissen - ein Kompromiss gefunden werden, da es

die optimale

Lsung nicht gibt.


Hersteller von Datenbanksystemen verfolgen diesbezglich unterschiedliche Strategien. Bei db4o
sind alle Transaktionen Read Committed. Es besteht aber zustzlich die Mglichkeit mithilfe von
Semaphores bestimmte kritische Bereiche zu locken, sprich als Serializable zu deklarieren. Eine
andere Art Bereiche zu locken, wre die Vergabe von Rechten und Passwrtern fr bestimmte
Daten der Datenbank.

159

10 Transaktionen

10.3 Semaphores
Das Konzept der Semaphores in der Datenbank db4o entspricht dem Konzept der synchronisierten Blcke in Java. Es gibt allerdings einen wesentlichen Unterschied: Synchronisierte Blcke,
regeln nur den Zugri auf Bereiche innerhalb einer Klasse, wohingegen Semaphores den Zugri
auf bestimmte Bereiche der gesamten Datenbank regeln. Ein Lock existiert nur einmal pro Klasse
und ein Semaphore existiert nur einmal pro Datenbank.
Sie haben mit den Semaphores die Mglichkeit verschiedene Bereiche zu locken, dies werden wir
jetzt genauer betrachten. Ich mchte Sie fr die Problematik sensibilisieren, aber keine Patentlsungen anbieten, da diese immer von verschiedenen Gren abhngt, wie z.B. der Anzahl der
Personen, die auf einzelnen Bereiche Zugri haben, dem Aufbau Ihrer Datenbank oder Ihrer
Anwendung.

10.3.1 Locken von Bereichen


Ein Semaphore kann ein beliebiger String sein, der am Anfang des Blockes mit der Methode
setSemaphore() gesetzt wird. Der zweite Parameter, der der Methode bergeben wird, ist eine
Zeitangabe in Millisekunden. Am Ende des Blockes wird die Semaphore mit releaseSemaphore()
und dem Namen der Semaphore wieder entfernt.
Betrachten wir unser erstes Beispiel: Wir erstellen zwei Threads und locken den Bereich, in dem
Links gendert werden. Dies ist der erste Thread, der den Link mit Namen "Home" ndert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

package Kap10;
import
import
import
import

Datenbankentwurf.Link;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;

public class ClientSynchronized extends Thread{

160

ObjectContainer client = null;


public void run() {
try{
client = Db4o.openClient
("localhost", 8080, "user1", "password");
/*Es wird ein Semaphore definiert.*/
if(client.ext().setSemaphore("Eins",1000)){
Link l = new Link("Home");
ObjectSet<Link> result = client.get(l);
l = result.next();
l.setName("Alt");
client.set(l);

10.3 Semaphores

28
29
30
31
32
33
34
35
36
37
38
39

/*Der Semaphore wird wieder entfernt.*/


client.ext().releaseSemaphore("Eins");
}
} catch(Exception e){
e.printStackTrace();
} finally{
client.close();
}
}
}
Listing 10.5: ClientSynchronized.java

und dies ist der Thread, der den Link mit Namen "Bcher" ndert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

package Kap10;
import
import
import
import

Datenbankentwurf.Link;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;

public class ClientSynchronized2 extends Thread{


ObjectContainer client = null;
public void run() {
try{
client = Db4o.openClient
("localhost", 8080, "user1", "password");
if(client.ext().setSemaphore("Eins",1000)){
Link l = new Link("Bcher");
ObjectSet<Link> result = client.get(l);
l = result.next();
l.setName("Neu");
client.set(l);
client.ext().releaseSemaphore("Eins");
}
} catch(Exception e){
e.printStackTrace();

161

10 Transaktionen

} finally{
client.close();
}
}
}

33
34
35
36
37

Listing 10.6: ClientSynchronized2.java


Auf diese Art wird

nicht ein bestimmtes Objekt gelockt, sondern ein bestimmter Bereich. Neh-

men wir einmal an, Sie haben tausend Objekte der Klasse Link und 100 Personen wollen gleichzeitig Links verndern, so knnte es zu Wartezeiten bis zu 100 Sekunden kommen ((1 Sekunde
x 100 Personen )/ 60 ), was so ca. 1,6 Minuten entspricht. Diese Zeit wrde bei 1000 Personen
sogar auf (( 1 Sekunde x 1000 Personen )/ 60) ca. 16 Minuten anwachsen.

10.3.2 Locken von Objekten


Dies entspricht nicht unseren Wnschen. Was ist die Lsung? Sie locken nicht ganze Bereiche fr
alle Objekte der gleichen Klasse, sondern Sie locken einen Bereich fr

ein bestimmtes Objekt.

Wie knnen wir dies tun? Wir koppeln den Namen des Semaphores an den OID, den Unique
Object Identier.
Fr jedes Objekt wird in der Datenbank eine Nummer vergeben, die eindeutig ist. Unten stehende Klasse LockManager habe ich dem db4o-Tutorial entnommen, das Sie mit der Datenbank
heruntergeladen haben und das sich im Verzeichnis tutorial bendet. Es wird also der OID ausgelesen und dieser wird dem Namen der Semaphore hinzugefgt. So erstellen Sie fr jedes Objekt
ein separaten Semaphore.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package Kap10;
import com.db4o.ObjectContainer;
import com.db4o.ext.ExtObjectContainer;
public class LockManager {

162

private final String SEMAPHORE_NAME = "locked: ";


private final int WAIT_FOR_AVAILABILITY = 300;
private final ExtObjectContainer _objectContainer;
public LockManager(ObjectContainer objectContainer){
_objectContainer = objectContainer.ext();
}
public boolean lock(Object obj){
/*Wir lesen den OID des Objektes aus.*/
long id = _objectContainer.getID(obj);
/*Wir setzen den Semaphore.*/
return _objectContainer.setSemaphore

10.3 Semaphores

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

(SEMAPHORE_NAME + id, WAIT_FOR_AVAILABILITY);


}
public void unlock(Object obj){
/*Wir lesen den OID des Objektes aus.*/
long id = _objectContainer.getID(obj);
/*Wir entfernen den Semaphore wieder.*/
_objectContainer.releaseSemaphore
(SEMAPHORE_NAME + id);
}

Listing 10.7: LockManager.java


Wir erstellen wieder einen Client in einem Thread und wir wenden die Methoden der Klasse
LockManager an. Diesen Thread nennen wir SynchronizedObject.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

package Kap10;
import
import
import
import

Datenbankentwurf.Link;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;

public class SynchronizeObject extends Thread{


public static void main(String[] args){
SynchronizeObject s = new SynchronizeObject();
s.start();
}
ObjectContainer client = null;
public void run() {
try{
client = Db4o.openClient
("localhost", 8080, "user1", "password");
/*Wir instanziieren ein Objekt der Klasse LockManager und
bergeben ihm als Parameter den ObjectContainer client.*/
LockManager lockManager = new LockManager(client);

163

10 Transaktionen

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

/*Wir lesen den Link mit Namen "Home" aus der Datenbank aus.*/
Link l = new Link("Home");
ObjectSet<Link> result = client.get(l);
l = result.next();
/*Wir bergeben den ausgelesenen Link der Methode lock(), die
ein Semaphore mit dem OID des ausgelesenen Links setzt.*/
if(lockManager.lock(l)){
l.setName("Alt");
client.set(l);
/*Der Semaphore wird mit der Methode unlock()wieder entfernt.*/
lockManager.unlock(l);
}
} catch(Exception e){
e.printStackTrace();
} finally{
client.close();
}
}
}
Listing 10.8: SynchronizeObject.java
Jetzt wird jeweils nur ein bestimmtes Objekt gelockt und nur dieses wird gelockt. Auf alle anderen
Objekte der Klasse Link kann jederzeit zugegrien werden, da sie weiterhin frei zugnglich sind.
Sollte noch jemand anders genau dieses Objekt verndern wollen, muss er nicht allzu lange
warten. Und es ist sehr unwahrscheinlich, dass mehr als 2 oder 3 Personen auf das gleiche Objekt
warten. Und selbst, wenn es sich bei der Wartezeit um einige Sekunden handelt, wird der Benutzer
dies nicht bemerken.

10.3.3 Lockingprozesse in Projekten


Wie knnen Lockingprozesse in greren Projekten optimiert werden? Die folgenden berlegungen sollen Ihnen Anregungen geben, wie die Antwortzeiten in einem Internet-Projekt erhht
werden knnen.
Sollten Sie mehrere Objekte locken wollen, wird es kompliziert. Nehmen wir das Beispiel Lschen einer WebSite, das wir bei den Transaktionen verwendet haben. Hier sind zwei Objekte
gleichzeitig betroen, nmlich ein Objekt der Klasse Formatierung und ein Objekt der Klasse
WebSite. Die Wahrscheinlichkeit, dass zwei Personen die gleiche Webseite gleichzeitig lschen
oder verndern wollen, ist sehr unwahrscheinlich.
Problematischer knnte es in folgendem Fall werden: Wenn es viele Personen gibt, die ein Objekt
der Klasse WebSite zur gleichen Zeit entweder anlegen, lschen oder ndern wollen und somit
auch gleichzeitig auf ein und dasselbe Formatierungsobjekt zugreifen. Diese Situation knnte
entzerrt werden, indem beim ndern und Anlegen, der Vorgang in seine Einzelteile zerlegt wird:

164

10.3 Semaphores

Das Hinzufgen oder ndern von Text, Bildern und PDFs wird jeweils in einer separaten Methode
und in einem separaten Formular durchgefhrt. So muss nicht beim Hinzufgen eines Bildes zu
einer Website auch auf das Formatierungsobjekt des Textes zugegrien werden.
Ein anderer Lsungsansatz wre das Denormalisieren unserer Daten, d. h. das teilweise rckgngig machen des Normalisierungsvorgangs. So wre es z.B. denkbar, ein Stringobjekt Formatierung
in der Klasse Text anzulegen und mit jedem Speichern eines Textes auch das Stringobjekt Formatierung mit zu speichern. Dies htte zwar auf der einen Seite zur Folge, dass z.B. der Namen
der Formatierung "font1" , mehrmals in der Datenbank vorkommen wrde, aber auf der anderen
Seite wrde es die Zugrisgeschwindigkeiten erheblich beschleunigen. Sollten Sie dies tun, msste
allerdings gewhrleistet sein, dass die Namen der Formatierungen korrekt geschrieben werden.
Dies wre ohne Probleme mithilfe eines Auswahlfeldes in einem Formular mglich.
Diese Vorgehensweise ist bei Rechnungen, die Artikel beinhalten, nicht zu empfehlen, da es auf
gar keinen Fall sinnvoll ist, mehrmals den gleichen Artikel in der Datenbank zu haben. Da es
auf keinen Fall machbar ist, alle Einzeldaten auf dem gleichen Stand zu halten und es auerdem
auch beim Auswerten der Daten, z.B. fr Umsatzzahlen, groe Probleme geben wrde. Hier wre
es sinnvoll, die Datenbank nach Artikelgruppen zu teilen. Hierbei muss darauf geachtet werden,
dass alle Daten, die in einer Rechnung vorkommen, sich auch in der gleichen Datenbank benden.
So ist es nicht mglich, dass eine Rechnung, Artikel aus zwei Datenbanken enthlt.
Hier an dieser Stelle noch einige Bemerkungen zum Arbeitsspeicher von db4o, den ich im Kapitel
Embedded Modus in einem Web-Projekt nher beschreiben werde. Sollte wie im Falle unseres
Content-Management-Systems die Zugrie durch Benutzer relativ hoch sein, aber der Inhalt
relativ selten verndert werden, kann der interne Arbeitsspeicher von db4o dazu benutzt werden,
die Antwortzeiten zu erhhen.

165

11 Einstieg in J2EE

11.1 Der Model-View-Controller: Klassen, Servlets und JSPs


Wie ist ein J2EE-Projekt mit Datenbankanbindung gegliedert? Das Projekt wird in verschiedene
Bereiche eingeteilt, und zwar in Datenbankentwurf, Datenbankabfragen, Programmierlogik und
Darstellung im Internet. Dies hat mehrere Vorteile: Erstens ist eine bersicht gewhrleistet, die
einen schnellen Zugri auf die einzelnen Elemente erleichtert und zweitens knnen so die einzelnen
Module wiederverwendet werden.
Wie heien die unterschiedlichen Dateien und wie werden sie abgespeichert? Es gibt in einem
J2EE-Projekt Java-Klassen, Servlets und JSPs. Datenbankentwurf und Datenbankabfragen werden als Java-Klassen abgespeichert, Programmierlogik als Servlets und Filter und die Darstellung
im Internet als JSP.
In dem Designmodell Model-View-Controller haben wir ein Modell, das aus drei Teilen besteht:
dem Model, dem Controller und dem View. Datenbankenwurf und abfragen werden unter dem
Oberbegri Model zusammengefasst, der Controller enthlt die Programmierlogik und das View
ist die Darstellung unserer Seite im Internet.

Abbildung 11.1: Model-View-Controller

Wie sieht die Struktur des J2EE-Projekts in NetBeans aus? Im Ordner DasErsteProjekt/src/Java
werden alle Java-Klassen, Servlets und Filter abgelegt; im Ordner web, auch webapp genannt,
alle JSP-Dateien, Bilder, PDFs und CSS-Dateien. Um Servlets und Filter von "normalen" JavaKlassen unterscheiden zu knnen, mssen diese in eine speziellen Datei eingetragen werden, der
so genannten web.xml, die sich im Ordner WEB-INF bendet. Sollten zustzliche Bibliotheken
dem Projekt hinzugefgt werden, mssen Sie vorher im Ordner WEB-INF ein Verzeichnis lib
anlegen.

167

11 Einstieg in J2EE

Abbildung 11.2: Projektstruktur eines Projektes in NetBeans

11.2 Zusammenspiel zwischen Servlet und JSP


Wie wir weiter oben gesehen haben, enthalten Servlets die Programmierlogik und JSPs die Darstellung im Internet. Lassen Sie uns das Zusammenspiel dieser beiden Dateien anhand eines
einfachen Beispiels nher betrachten: Ein Servlet ist eine normale Java-Klasse, der spezielle
Funktionalitten zugewiesen werden und die Methoden der Vaterklasse HttpServlet erbt und
berschreibt. Unser erstes Servlet berschreibt die Methoden doGet() und doPost(), wobei die
doGet()-Methode dazu da ist, Daten zu empfangen, die mit GET verschickt wurden und die
doPost()-Methode mit POST. Weiter unten werden wir sehen, was POST und GET von einander unterscheidet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package Kap11;
import
import
import
import
import

java.io.IOException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.ServletException;

public class ErstesServlet extends HttpServlet {

168

protected void doGet(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
}

doGet(request, response);

11.2 Zusammenspiel zwischen Servlet und JSP

22
23

}
Listing 11.1: Unser erstes Servlet

Da wir dieses Servlet im Internet verentlichen wollen, brauchen wir einen Webcontainer, nmlich Tomcat. In unserer IDE NetBeans ist Tomcat bereits eingebunden. Sie nden Tomcat in
NetBeans, indem Sie links oben auf Runtime klicken und dann auf Servers.

Abbildung 11.3: Tomcat in NetBeans


Ein Servlet wird in die web.xml eingetragen, so wei Tomcat, in welchem Ordner danach gesucht
werden muss. Was ist die web.xml? Der Web Deployment Descriptor web.xml ist eine Datei,
die XML-konforme Befehle enthlt, und in die in einem Webprojekt wichtige Informationen
eingetragen werden mssen. Diese Informationen sind wichtig fr den Webcontainer Tomcat, der
die Aufgabe bernimmt z.B. ein Servlet mit bestimmten Ausprgungen im Internet darzustellen.
Wenn Sie Eintrge in der web.xml erstellen, ist es nicht notwendig, tief greifende XML-Kenntnisse
zu besitzen, es gengen einige wenige Grundlagen. Jedes Element besteht aus zwei Teilen, einem
Anfangs-Tag und einem End-Tag. In jedem Element knnen sich wieder weitere Elemente benden. Im Servlet-Element mit dem Anfangs-Tag <servlet> und dem End-Tag </servlet> gibt es
zwei weitere Elemente, hier legen Sie den Namen des Servlets fest und tragen ein, in welchem Ordner das Servlet abgelegt wurde. Im URL-Pattern-Element des Servlet-Mapping steht die Bezeichnung unter der Sie das Servlet erreichen knnen: Der Pfad ndert sich von Kap02/ErstesServlet
in die abgekrzte Form /ErstesServlet. Dies hat drei Vorteile: Erstens mssen Sie den Pfad nur
noch an einer Stelle verndern, zweitens mssen Sie nicht immer den kompletten Pfad eingeben,
und drittens wird die Ordnerstruktur fr den User komplett unsichtbar.

1
2
3
4
5
6
7
8
9
10
11

<?xml version="1.0" encoding="UTF-8"?>


<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<!-- Name des Servlets -->
<servlet-name>ErstesServlet</servlet-name>

169

11 Einstieg in J2EE

<!-- Ort, an dem das Servlet gespeichert wurde -->


<servlet-class>Kap11.ErstesServlet</servlet-class>

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

</servlet>
<servlet-mapping>
<!-- Name des Servlets -->
<servlet-name>ErstesServlet</servlet-name>
<!-- Aufruf des Servlets in der URL -->
<url-pattern>/ErstesServlet</url-pattern>
</servlet-mapping>
</web-app>
Listing 11.2: Servlet-Mapping (web.xml)
Kommen wir zu unserem ersten Formular, das Daten an unser Servlet sendet. Wie Sie sehen
knnen, besteht eine JSP-Datei hauptschlich aus HTML; Java wird nur an bestimmten Stellen
eingebettet. So holt uns der Java-Befehl <%=request.getContextPath()%> den aktuellen Pfad
des Servlets aus der URL. Dieser kann unterschiedlich sein, je nachdem ob das Projekt sich lokal
auf Ihrem Rechner bendet oder im Internet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Erstes Formular</title>
</head>
<body>
<!--Sendet Daten an das Servlet mit Namen ErstesServlet -->
<form name=""
action="<%=request.getContextPath()%>/ErstesServlet"
method="GET">
<input type="text" name="Formatierung" value=""/>
<input type="submit" name="Eingabe" value="Eingabe"/>
</form>
</body>
</html>
Listing 11.3: Unser erstes Formular(erstesJSP.jsp)

170

11.2 Zusammenspiel zwischen Servlet und JSP

Unten stehende Abbildung stellt die Beziehung zwischen JSP und Servlet dar. Es werden in
das Formular Daten eingegeben, die direkt mit GET an das Servlet und die Methode doGet()
gesendet werden.

Abbildung 11.4: Beziehung zwischen Servlet und JSP

Diese Arbeitsteilung stellt eine enorme Erleichterung fr den Programmierer und den mit ihm
zusammenarbeitenden Webdesigner dar. Eine JSP-Datei, bei der noch klar die HTML-Struktur
vorhanden ist, kann jederzeit beinahe problemlos von einem Webdesigner verndert und ergnzt
werden. Deshalb sollten auch jegliche Javaprogrammierzeilen auf ein Minimum beschrnkt sein.

Was passiert intern mit einem JSP? Es gibt noch eine andere Beziehung zwischen Servlet und
JSP, die bisher nicht ersichtlich war: Das JSP wird in ein Servlet umgewandelt, sobald das Projekt
von Tomcat fr das Internet fertig "verpackt" wird. Wo bendet sich dieses Servlet? NetBeans
hat es geschickt vor Ihnen versteckt. Sie mssen in die Projects-Ansicht wechseln und mit der
rechten Maustaste das JSP anklicken und anschlieend View Servlet.

171

11 Einstieg in J2EE

Abbildung 11.5: So gelangen Sie in die Servlet-Ansicht des JSP


So net sich folgende Java-Klasse, die Ihnen zeigt wie viel Arbeit Ihnen durch den Einsatz der
Java Server Pages erspart bleibt. Weiter unten in den Abschnitten ber Servlets und JSPs werden
wir auf diese Zusammenhnge nher eingehen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

package Kap11;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class erstesJSP_jsp
extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {

172

private static java.util.List _jspx_dependants;


public Object getDependants() {
return _jspx_dependants;
}
public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;

11.2 Zusammenspiel zwischen Servlet und JSP

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

Object page = this;


JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
try {
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html");
pageContext = _jspxFactory.getPageContext(this, request,
response, null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("<!DOCTYPE HTML PUBLIC " +
"\"-//W3C//DTD HTML 4.01 Transitional//EN\"\n");
out.write("\"http://www.w3.org/TR/html4/loose.dtd\">\n");
out.write("\n");
out.write("<html>\n");
out.write("
<head>\n");
out.write("
<title>Erstes Formular</title>\n");
out.write("
</head>\n");
out.write("
<body>\n");
out.write("
<form name=\"\" action=\"");
out.print(request.getContextPath());
out.write("\n");
out.write("
/ErstesServlet\" method=\"GET\">
" +
" \n");
out.write("
<input type=\"text\" name=\"Formatierung" +
"\" value=\"\"/>\n");
out.write("
<input type=\"submit\" name=\"Eingabe\" " +
"value=\"Eingabe\"/>\n");
out.write("
</form>\n");
out.write("
</body>\n");
out.write("</html>\n");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (_jspx_page_context != null) _jspx_page_context.
handlePageException(t);
}
} finally {
if (_jspxFactory != null) _jspxFactory.
releasePageContext(_jspx_page_context);

173

11 Einstieg in J2EE

76
77
78

Listing 11.4: JSP als Servlet

11.2.1 Versenden von Daten mit POST und GET


Daten werden im Internet gem des HTTP-Protokolls versendet, das eine einfache AnfrageAntwort-Beziehung zwischen dem Benutzer und dem Server darstellt. Der Benutzer fllt ein
Formular aus und sendet diese Formulardaten zum Server, der anschlieend Daten als Antwort
zurcksendet. Der Benutzer fragt an, der Server antwortet. Der englische Fachbegri fr die
Anfrage des Client lautet Request und die Antwort des Servers Response. Jeder Request luft in
einem separaten Thread.

Abbildung 11.6: Die Request-Response-Beziehung


Es gibt zwei Methoden, die es Ihnen mglich machen, Fragen und Antworten im Internet zu
versenden: POST und GET. Welche Unterschiede bestehen zwischen den beiden Methoden POST
und GET? Bei GET werden die Formulardaten an die URL mit einem Fragezeichen angehngt:
http://localhost:8084/DasErsteProjekt/eingabeFormatierung?name=font1&Eingabe=Eingabe
Dies hat vier Nachteile: Erstens sind die Daten fr den Benutzer sichtbar; dies wre beim bersenden von geheimen Daten, wie z.B. Passwrter nicht sinnvoll. Zweitens knnen Sie zwar gem
HTTP-Protokoll beliebig viele Daten versenden, aber praktisch ist diese Datenmenge in vielen
Browsern begrenzt. Und zum Dritten speichert der Browser u.U. die Daten im URL-Cache. Viertens knnen Sie nur Textdaten versenden und keine binren Daten. Diese Nachteile fallen alle
weg, wenn Sie die Methode POST benutzen. POST versendet Daten im so genannten Request
Message Body, der fr den Benutzer nicht sichtbar ist. Auerdem knnen Sie mit POST binre
Daten versenden.
So lsst sich kurz zusammengefasst sagen: Groe Datenmengen, die vom Benutzer nicht eingesehen werden sollen, versenden Sie am besten mit POST. Zu bungszwecken werde ich im
folgenden alle Daten mit GET versenden, da es hier oft notwendig sein wird, die Daten, die
versendet werden, als Anhang der URL sehen zu knnen.

11.3 Servlets

11.3.1 Allgemeines
Ursprnglich standen den Programmierern in der Java-Webprogrammierung nur Servlets zur Verfgung. Vor Einfhrung der JSPs musste der Programmierer mithilfe eines Servlets die HTMLAusgabe im Browser programmieren. Weiter oben haben Sie bereits gesehen, wie ein JSP aussieht,
wenn es von Tomcat in ein Servlet umgewandelt wurde.

174

11.3 Servlets

Wie knnen Sie ein Servlet mit HTML-Ausgabe erstellen? Mit Hilfe eines PrintWriter-Objektes.
Der PrintWriter gehrt zum java.io-Package und besitzt die Funktion, Text in eine Datei auslesen zu knnen. Hierbei handelt es sich um einen Zeichenstrom, der Text zeichenweise in einen
Speicher-Puer und dann in eine Datei ausliest. Im Falle von Servlets wird dieser Text im Browser
ausgegeben. Das PrintWriter-Objekt erhalten Sie, wenn Sie auf dem HttpServletResponse-Objekt
die getWriter()-Methode ausfhren. Mit der println()-Methode knnen Sie dann anschlieend die
HTML-Seite erstellen. Wie Sie im HelloWorldServlet sehen knnen, ist dies eine sehr mhselige
Arbeit, die Ihnen heute durch JSPs abgenommen wird.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

package Kap11;
import
import
import
import
import
import

java.io.IOException;
java.io.PrintWriter;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;

public class HelloWorldServlet extends HttpServlet {


public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();

out.println("<html>");
out.println(" <head>");
out.println("
<title>HelloWorld</title>");
out.println(" </head>");
out.println(" <body>");
out.println("
Hello World");
out.println(" </body>");
out.println("</html>");

public void doPost(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Listing 11.5: HelloWorldServlet.java

175

11 Einstieg in J2EE

Das Objekt der Klasse HttpServletResponse mit Namen response, das der Methode doGet() als
Parameter bergeben wird, stellt Ihnen alle Methoden zur Verfgung, die notwendig sind, Daten
im Browser auszugeben. Rufen Sie nun das Servlet auf, erscheint Hello World im Browser:

Abbildung 11.7: Ausgabe des HelloWorldServlets

11.3.2 Methoden des Interface HttpServletRequest


Das Interface HttpServletRequest erweitert das ServletRequest-Interface und stellt Methoden
zur Verfgung, die es Ihnen im Servlet mglich machen, Daten auszulesen, die vom JSP an das
Servlet gesendet worden sind. Sollten Sie jetzt nach diesem Interface in Ihrer Java-Dokumentation
(Javadocs / API Documentation) suchen, werden Sie feststellen, dass es dort kein entsprechendes
Interface gibt. Informationen zu J2EE-Klassen nden Sie in der entsprechenden J2EE-API, die
Sie von der Sun-Website herunterladen knnen.
Mit der Methode getParameter() lsst sich das Feld mit dem Namen Formatierung auslesen, das
vom Formular im JSP mit Namen erstesJSP.jsp an das Servlet mit Namen ErstesServlet.java
gesendet worden ist. Das Formularfeld Formatierung wird im Servlet als Parameter ausgelesen.
Ein Parameter kann nicht verndert werden; er ist nur lesbar. Die entsprechende Befehlszeile in
der doGet-Methode des Servlets ErstesServlet lautet dann wie folgt:
r e q u e s t . getParameter (" Formatierung " ) ;
Normalerweise endet der Request an dieser Stelle, da es sich um eine Weiterleitung vom Client
zum Server handelt. Sollte Sie allerdings die Daten weiterschicken wollen, besteht die Mglichkeit
die Daten des Requests vom Server an den Client zurckzusenden. Dies macht es Ihnen z.B. mglich, Daten wieder parat zu haben, wenn in einem Adressformular ein Pichtfeld nicht ausgefllt
wurde und Sie nicht wollen, dass der Kunde alle Felder nochmals eingeben muss. Sie senden die
Daten des Request mit getRequestDispatcher() weiter, wobei Sie die Zielseite angeben mssen:
r e q u e s t . g e t R e q u e s t D i s p a t c h e r ( " / Kap02 / e r s t e s J S P . j s p " ) . f o r w a r d ( r e q u e s t ,
response ) ;
Zum Schlu noch die bereits erwhnte Methode getContextPath(), die den tatschlichen Ort und
die Pfadangabe des Projektes wiedergibt:
r e q u e s t . getContextPath ( )
Das Interface HttpServletRequest besitzt noch mehrere Methoden bezglich Sessions, die wir
weiter unten nher betrachten werden.

11.3.3 Die Methode sendRedirect() des Interface HttpServletResponse


Die Methode response.sendRedirect() unterscheidet sich von der bereits kennengelernten Methode request.getRequestDispatcher(), insofern, als sie nur auf eine andere Seite weiterleitet.

176

11.3 Servlets

Schickt der Benutzer z.B. Daten aus einer Bestellung zum Server und schickt der Server diese Daten mit der Methode response.sendRedirect() weiter, stehen diese Daten auf der Zielseite
nicht mehr zur Verfgung. Achtung: Hier mssen Sie der Methode zustzlich mit der Methode
request.getContextPath() den Pfad des Projektes bergeben.
r e s p o n s e . sendRedirect ( r e q u e s t . getContextPath ( ) +
" / Kap02 / e r s t e s J S P . j s p " ) ;
Leiten Sie mit der Methode sendRedirect() Ihre Seite weiter, gehen somit alle Informationen
verloren, die Sie vom Formular erhalten haben.

11.3.4 Sessions und die zugehrigen Methoden


Wir haben gesehen, dass die Informationen, die vom Formular an das Servlet gesendet werden,
nur whrend des Zeitraums der Anfrage/des Requests existieren. Nehmen wir an, Sie haben eine
Bestellung, die aus verschiedenen Seiten besteht, wie z.B. aus einem Warenkorb, Artikel- und
Kundenstammdaten, so bentigen Sie diese Formulardaten whrend des ganzen Bestellvorgangs.
Diese Funktion erfllt eine Session.
Die Session ist Teil des Requests/der Anfrage und existiert ab dem Zeitpunkt, an dem Sie der
doGet()-Methode des Servlets das HttpServletRequest bergeben. Der Server beendet nach einer
bestimmten Zeit die Session automatisch, wenn der Benutzer ber einen lngeren Zeitraum keine
Daten mehr an den Server schickt. Wollen Sie selbst die Session lschen, geht dies mit invalidate(),
wobei Sie sich zuerst mit der Methode getSession() einen Zugri auf die Session des Requests
verschaen mssen:
request . getSession ( ) . invalidate ( ) ;
Knnen Sie auch den Zeitraum festlegen, nachdem die Session beendet wird? Ja, Sie legen einen
Timeout fr Ihre Session in der web.xml fest, indem Sie in das Timeout-Element des SessionCong-Elements eine Zeitangabe in Minuten schreiben. Was passiert, wenn Sie 0 oder eine negative Zahl eingeben? Bei 0 wird die Session sofort beendet und bei einer negativen wird sie nie
beendet.
< s e s s i o n c o n f i g >
< s e s s i o n t i m e o u t >30</ s e s s i o n t i m e o u t >
</ s e s s i o n c o n f i g >
Wie knnen Sie der Session Werte bergeben? Mit der Methode setAttribute(String name, Object
value). Diese Methode besitzt zwei bergabewerte: Der Erste gibt dem Attribut seinen Namen
und der Zweite ist eine Variable oder ein Objekt. In unten stehendem Beispiel erstellen wir eine
Fehlermeldung, die wir als Attribut der Session bergeben:
String

f e h l e r m e l d u n g = new

String (" Sie

haben

das

Feld

nicht

ausgefllt !";
request . g e t S e s s i o n ( ) . s e t A t t r i b u t e (" e r r o r " , fehlermeldung ) ;
Diesen String knnen sie im Servlet mit der Methode getAttribute() auslesen:
request . g e t S e s s i o n ( ) . getAttribute (" e r r o r " ) ;
Und sollten Sie das Attribut nicht mehr brauchen, knnen Sie es mit der Methode removeAttribute() wieder lschen:
request . g e t S e s s i o n ( ) . removeAttribute (" e r r o r " ) ;

177

11 Einstieg in J2EE

Achtung: Die Sessions funktionieren nur, wenn der Benutzer nicht die hchste Sicherheitsstufe bezglich Cookies eingestellt hat. Es gibt zweierlei Lsungen fr dieses Problem: Entweder
Sie knnen auf Sessions verzichten und nur Request-Attribute verwenden, die Sie immer mit
dem Request-Dispatcher weitersenden oder Sie machen es wie Yahoo, die Ihre Benutzer dazu
auordern, die Cookies wieder einzuschalten.

11.3.5 Attribute, Parameter und Geltungsbereiche


Wie die Methoden setAttribute(), getAttribute() und removeAttribute() zeigen, knnen Attribute erstellt, ausgelesen und wieder gelscht werden, wohingegen Parameter, die direkt aus dem
Request mit request.getParameter("Formatierung"); des Interfaces HttpServletRequest ausgelesen werden, nur lesbare (read-only) Informationen enthalten.
Gibt es Attribute nur fr Sessions? Nein! Es gibt sie fr folgende Geltungsbereiche: Sessions,
Requests und Applikationen/Contexte. Wodurch unterscheiden sich die Geltungsbereiche, die
auch Scope genannt werden? Der Request existiert whrend der Anfrage, sprich in der Zeit, in
der Daten vom Client zum Server gesendet werden. Die Session umfasst einen lngeren Zeitraum,
der exakt festgelegt werden kann, und der in Regel so lange dauert, wie ein Benutzer sich auf
einer bestimmten Website bendet. Wohingegen der Context die Webapplikation selbst ist, auf
den von allen Bestandteilen der Webapplikation zugegrien werden kann und die keine zeitliche
Begrenzung kennt.
Fr den Request knnen Sie ein Attribut folgendermaen erstellen:
request . s e t A t t r i b u t e (" e r r o r " ,

fehlermeldung ) ;

Beim Context lautet die entsprechende Befehlszeile wie folgt:


getServletContext ( ) . s e t A t t r i b u t e (" e r r o r " ,

fehlermeldung ) ;

Wie sieht es mit den Parametern aus? Gibt es sie auch fr alle drei Geltungsbereiche? Es gibt sie
auch fr den Context und fr den Context des Servlets, aber nicht fr Sessions. Fr Context- und
Servlet-Context-Parameter gibt es keine Setter-Methode, da sie in der web.xml deniert werden.
Im entsprechenden Kapitel weiter unten werden wir besprechen, wie sie wieder ausgelesen werden
und welche Aufgabe sie haben.

11.3.6 Ein praktisches Beispiel


Lassen Sie uns anhand eines Beispiels das Wichtigste zusammenfassen. Wir beginnen wie folgt:
Erstens: Wir erstellen ein Servlet, nennen es ZweitesServlet, und tragen es in die web.xml ein.
Zweitens: Wir erstellen ein JSP mit Namen zweitesJSP.jsp und schicken von diesem JSP Daten
an das Servlet.

1
2
3
4
5
6
7
8
9
10

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>ClientServer</title>
</head>
<body>

178

<form name=""

11.3 Servlets

11
12
13
14
15
16
17
18
19
20

action="<%=request.getContextPath()%>/ZweitesServlet"
method="GET">
<input type="text" name="Formatierung" value=""/>
<input type="submit" name="Eingabe" value="Eingabe"/>
</form>
</body>
</html>
Listing 11.6: Unser zweites JSP(zweitesJSP.jsp)

Anschlieend lesen wir in untenstehendem Servlet die Daten des Formulars mit getParameter()
aus, speichern den Namen der Formatierung mit setAttribute() als Session-Attribut und leiten
das Servlet mit der Methode getRequestDispatcher() an ein JSP weiter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

package Kap11;
import
import
import
import
import

java.io.IOException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.ServletException;

public class ZweitesServlet extends HttpServlet {


protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
/*Ist im zweitesJsp.jsp auf submit mit
Namen Eingabe geklickt worden,
ergibt unten stehender Ausdruck true*/
if(request.getParameter("Eingabe")!= null){
/*Es wird das Formularfeld Formatierung
aus dem Request ausgelesen*/
String formatierungName = request.getParameter
("Formatierung");
/*Der String formatierungName wird der
Session als Attribut bergeben*/
request.getSession().setAttribute
("Formatierung", formatierungName);
/*Der Request wird an das JSP weitergeleitet*/
request.getRequestDispatcher("/Kap02/drittesJSP.jsp").
forward(request, response);

179

11 Einstieg in J2EE

33
34
35
36
37
38
39
40
41
42

protected void doPost(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Listing 11.7: Unser zweites Servlet
Wie auf Parameter des Requests und auf Attribute der Session in einem JSP zugegrien wird,
werden wir uns im JSP namens drittesJSP.jsp im Unterkapitel JSPs nher ansehen.
Sie werden sich jetzt sicherlich fragen: Wie starte ich mein Projekt? Whlen Sie im Men den
Menpunkt Run und Run Main Project aus, oder wenn Ihr Projekt nicht das Main Project ist,
klicken Sie in der Ansicht Projects mit der rechten Maustaste auf Ihr Projekt und anschlieend
auf Run Project.
Der eingebettete Web-Container Tomcat net einen virtuellen Server, den so genannten Localhost. Dieser ist unter URL://localhost:8080 oder URL://localhost:8084 zu erreichen. Bei mir ist
er unter dem Port 8084 zu erreichen, da ich Tomcat zweimal installiert habe, einmal nur Tomcat
und einmal Tomcat mit NetBeans. Der Startbildschirm von Tomcat, auf Deutsch Kater, sieht
wie folgt aus:

Abbildung 11.8: Startbildschirm von Tomcat


Sobald sich Ihr Browser net, geben Sie folgende Adresse ein:
http://localhost:8084/DasErsteProjekt/Kap02/zweitesJSP.jsp

180

11.3 Servlets

und Sie knnen die folgende Seite in Ihrem Browser sehen:

Abbildung 11.9: Unser zweites Formular


Dieser Vorgang nennt sich Deployment. Was passiert whrend dieses Vorgangs? Es werden alle
wichtigen Dateien in einer WAR-Datei zusammengefasst; so ist es mglich eine Applikation im
Internet zu verentlichen. Platzieren Sie die WAR-Datei im webapps-Verzeichnis von Tomcat
und der Inhalt wird automatisch entpackt und Ihre Webapplikation kann benutzt werden. Wie
setzt sich diese Datei zusammen? Es wird die Struktur des Ordners web, auch webapp genannt,
bernommen und es wird ein zustzlicher Ordner classes fr die kompilierten Java-Klassen erstellt. Dieser Ordner classes wird im Verzeichnis WEB-INF angelegt.
Die WAR-Datei nden Sie in NetBeans im Ordner dist:

Abbildung 11.10: War-Datei


So bleibt eine letzte Frage: Woher wei Tomcat, wie unser Projekt heit? Dies wird im Context
path in der context.xml festgelegt, die sich im Ordner META-INF bendet und die NetBeans
ganz am Anfang fr Sie angelegt hat.

1
2

<?xml version="1.0" encoding="UTF-8"?>


<Context path="/DasErsteProjekt"/>
Listing 11.8: context.xml

181

11 Einstieg in J2EE

11.4 JSP

11.4.1 Grundlagen
Java Server Pages bestehen aus HTML und CSS, in das Java eingebettet wird. Da JSPs und
Servlets sich die Arbeit teilen, steht in einem JSP nur noch ein Minimum an Java und es werden in
der Regel nur noch Daten ein- oder ausgegeben, da sich die Programmierlogik im Servlet bendet.
Die HTML- und CSS-Struktur sollte immer klar erkennbar bleiben, so knnen Sie problemlos
mit Webdesignern zusammenarbeiten, die Ihnen das Design zur Verfgung stellen.
Beginnen wir mit den CSS-Formaten unseres Projektes, die sich alle in einer Datei stil.css benden, die weiter unten komplett eingefgt wurde. Ich will hier an dieser Stelle nur einige wenige
CSS-Formate nher erlutern, da der Schwerpunkt des Buches auf Datenbankanbindung mit db4o
liegen soll und ich nur die Grundstruktur von JSP-Seiten kurz darstellen mchte. Unsere erste
JSP-Seite soll aus drei Teilen bestehen: oben, links und unten. Die Bereiche haben normalerweise
unterschiedliche Funktionen, so bendet sich im oberen Teil oft das Firmenlogo, im linken die
Menleiste und im unteren der Text und die Bilder.

Abbildung 11.11: Grundstruktur einer JSP-Seite im Browser


In unten stehender JSP-Seite, die im Moment nur aus HTML und CSS besteht, werden drei CSSKlassen mit einem div-Tag zugewiesen. CSS-Klassen knnen sowohl mit einem div-Tag als auch
mit einem span-Tag zugewiesen werden, wobei der Unterschied darin besteht, dass beim div-Tag
zustzlich ein Zeilenumbruch in die HTML-Seite eingefgt wird. Das CSS-Format boxOben legt
den oberen Teil fest, boxLinks den linken und boxRechts den rechten.

1
2

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">

182

11.4 JSP

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

<html>
<head>
<!--hier wird festgelegt auf welche CSS-Datei
zugegriffen wird-->
<link rel="stylesheet" href="../Styles/stil.css" type="text/css">
<title>Erstes JSP mit CSS</title>
</head>
<body>
<div class="boxOben">
oben
</div>
<div class="boxLinks">
links
</div>
<div class="boxRechts">
unten
</div>
</body>
</html>
Listing 11.9: Erstes JSP mit CSS-Formatierungen(jspUndStile.jsp)

In unten stehender Datei stil.css gibt es mehrere CSS-Klassen, die unterschiedliche Formatierungsaufgaben erfllen:
1. Die CSS-Klassen, die unsere HTML-Seite in drei Bereiche einteilen: boxOben, boxLinks
und boxRechts.
2. Die Textformatierungen font1, font2, font3 und font4 ermglichen es Ihnen, die Schrift,
Schriftfarbe, Schriftgre und Ausrichtung von Texten zu variieren.
3. Das Format fr Hyperlinks menu legt das Format fr den div-Bereich eines Hyperlinks der
linken Menleiste fest. Die dazugehrige CSS-Klasse menu a formatiert den Normalzustand
eines Hyperlinks und menu a:hover den Rollover-Eekt.
4. Mit menub wird der div-Bereich der Links fr die PDFs formatiert, mit menub a der
Normalzustand des Hyperlinks und mit menu a:hover der dazugehrige Rollover-Eekt.
5. Die Klasse button formatiert die Farbe und Schriftfarbe eines Submit-Buttons im Formular.
6. Die Klasse list ul legt die CSS-Formate fr die Aufzhlung, die Klasse list li formatiert die
darin enthaltenen Aufzhlungszeichen und list die dazugehrigen Hyperlinks. Diese Formatgruppe wird dazu benutzt in unserem Content-Management-System die obere Menleiste

183

11 Einstieg in J2EE

zu erstellen, da so sichergestellt wird, dass sich die Hyperlinks nebeneinander benden und
nicht untereinander.
7. Die Klassen box1, variablebox, box2 und box3 teilt unsere Seite in vier Teile: Die variablebox ist dafr vorgesehen ist, die obere Menleiste zu beinhalten, box1 stellt Platz fr ein
Titelbild bereit, box2 dient der linken Menleiste und box3 Text und Bildern als Rahmen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

/*Legt die Hintergrundfarbe des HTML-Dokumentes fest*/


body{
background-color:#4E799E;
}
/*legt das Format fr den div-Bereich der linken Menleiste fest*/
.menu {
font-family:Comic Sans MS;
color:#ffffcc;
font-size:10pt;
text-decoration:none;
text-align:center;
width:150px;
height: 25px;
padding:10px;
margin:2px;
}
/*legt das Format fr den Normalzustand der linken Menleiste fest*/
.menu a{
font-family:Comic Sans MS;
text-align:center;
font-size:10pt;
text-decoration:none;
width:150px;
height: 25px;
color:#ffffcc;
background-color:#2B3E5E;
display:block;
padding:2px;
margin:2px;}
/*legt das Format fr den Rollover-Effekt der linken Menleiste fest*/
.menu a:hover {
font-family: Comic Sans MS;
font-size:10pt;
text-align:center;
width:150px;
height: 25px;
text-decoration:none;
color:#336699;
display:block;

184

11.4 JSP

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

padding:2px;
margin:2px;
}
/*legt das Format fr den div-Bereich der Hyperlinks
fr die PDFs fest, die sich unten in der Mitte befinden */
.menub {
font-family:Comic Sans MS;
color:#ffffcc;
font-size:10pt;
text-decoration:none;
text-align:center;
width:150px;
height: 25px;
padding:10px;
margin:2px 120px 2px 105px;}
/*legt den Normalzustand des Hyperlinks fr das PDF fest*/
.menub a{
font-family:Comic Sans MS;
text-align:center;
font-size:10pt;
text-decoration:none;
width:150px;
height: 25px;
color:#ffffcc;
background-color:#2B3E5E;
display:block;
padding:2px;
margin:2px 120px 2px 105px;}
/*legt den Rollover-Effekt des Hyperlinks fr das PDF fest*/
.menub a:hover {
font-family: Comic Sans MS;
font-size:10pt;
text-align:center;
width:150px;
height: 25px;
text-decoration:none;
color:#336699;
display:block;
padding:2px;
margin:2px 120px 2px 105px;
}
/*Hier werden vier verschiedene Schriftgren festgelegt*/
.font1 {
font-family:Comic Sans MS;
font-size:20pt;

185

11 Einstieg in J2EE

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

color:#ffffcc;
padding:10px;
margin:10px;
}
.font2 {font-family:Comic Sans MS;
font-size:14pt;
color:#FFFFCC;
padding:10px;
margin:10px;
}
.font3 {
font-family:Comic Sans MS;
font-size:12pt;
color:#FFFFCC;
padding:10px;
margin:10px;}
.font4 {
font-family:Comic Sans MS;
font-size:20pt;
text-align: center;
color:#FFFFCC;
padding:10px;
margin:10px;}
/*Hier wird Farbe und Schriftfarbe fr den Submit-Button festgelegt*/
.button{
font-family:Comic Sans MS;
color:#ffffcc;
background-color:#2B3E5E;
font-size:10pt;
text-decoration:none;
text-align:center;
width:170px;
border:0px;
margin:2px 2px 2px 2px;
}
/*Format fr Aufzhlung*/
.list ul{
margin: 0;
padding: 0px;
list-style: none;
background-color:#2B3E5E;
text-align:center;
}

186

11.4 JSP

141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

/*Format fr einzelne Aufzhlungspunkte*/


.list li{
float:right;
width:150px;
list-style: none;
text-align:center;
margin: 0 0 0 10px;
}
/*legt das Format fr den div-Bereich der Hyperlinks
fr die Menleiste fest, die sich rechts oben befindet */
.list {
font-family:Comic Sans MS;
color:#ffffcc;
font-size:10pt;
text-decoration:none;
text-align:center;
width:100%;
height: 100%;
display: block;
padding:5px 0 5px 0;
}
/*legt das Format fr den Normalzustand der Hyperlinks
fr die Menleiste fest, die sich rechts oben befindet */
.list a{
font-family:Comic Sans MS;
text-align:center;
font-size:10pt;
text-decoration:none;
color:#ffffcc;
background-color:#2B3E5E;
width:100%;
height: 100%;
display: block;
padding:5px 0 5px 0;
}
/*legt das Format fr den div-Bereich der Hyperlinks
fr die Menleiste fest, die sich rechts oben befindet */
.list a:hover {
font-family: Comic Sans MS;
font-size:10pt;
text-align:center;
width:100%;
height: 100%;
text-decoration:none;
color:#336699;
display:block;

187

11 Einstieg in J2EE

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238

padding:5px 0 5px 0;
}
/*Kasten der Hhe 100 und der Breite 800, der sich ganz oben befindet*/
.box1{
position:absolute;
top: 0px;
left: 0px;
height: 100 px;
width: 800px;
}
/*Kasten der Hhe 50 und der Breite 800, der sich
100 px vom oberen Rand weg befindet*/
.variablebox{
position:absolute;
max-height: 50px;
top: 100px;
left: 0px;
height: 50px;
width: 800px;
text-align:center;
}
/*Kasten der Hhe 400 und der Breite 200, der sich
150 px vom oberen Rand weg befindet*/
.box2{
position:absolute;
top: 150px;
left: 0px;
float:left;
width: 200px;
height: 400px;
padding: 0px 0px 0px 0px;
margin: 0px;
}
/*Kasten der Hhe 400 und der Breite 600, der sich
150 px vom oberen und 200px vom linken Rand weg befindet*/
.box3{
position:absolute;
top: 150px;
left: 200px;
text-align:center;
width: 600px;
height: 400px;
color:#FFFFCC;
}

188

11.4 JSP

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

/*Kasten der Hhe 100 und der Breite 800 px, der sich direkt
am linken oberen Rand befindet*/
.boxOben{
position:absolute;
top: 0px;
left: 0px;
width: 800px;
height: 100px;
border:1px solid black;
}
/*Kasten der Hhe 400 und der Breite 200 px,
der sich 100 px weg vom oberen Rand befindet*/
.boxLinks{
position:absolute;
top: 100px;
left: 0px;
/*float:left bedeutet, dass sich das Element links
befindet und von dem nchsten Element umflossen wird*/
float:left;
width: 200px;
height: 400px;
border:1px solid black;
}
/*Kasten der Hhe 400 und der Breite 600 px, der sich 100 px weg
vom oberen Rand und 200 px weg vom linken Rand befindet*/
.boxRechts{
position:absolute;
top: 100px;
left: 200px;
text-align:center;
width: 600px;
height: 400px;
border:1px solid black;
}

Listing 11.10: CSS-Formate(stil.css)

Wie sieht die Grundstruktur unseres Content-Management-Systems aus? Wir haben vier Bereiche: box1, variablebox, box2 und box3. Wir haben zwei Menleisten eine linke und eine obere
und der restliche Platz steht uns fr Text, Bilder und Hyperlinks fr PDFs zur Verfgung.

189

11 Einstieg in J2EE

Abbildung 11.12: Grundstruktur unseres Content-Management-Systems


In unserem JSP werden die CSS-Formate wieder sowohl mit span- als auch mit div-Tags zugewiesen. Unsere obere Menleiste besteht aus dem HTML-Tag ul fr Aufzhlungen und dem li-Tag
fr die darin enthaltenen Aufzhlungspunkte. Diese Aufzhlungspunkte enthalten wiederum die
Hyperlinks unserer Menleiste, die auf diese Art und Weise nebeneinander aufgereiht werden und
nicht - wie bei der linken Menleiste - untereinander.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" href="../Styles/stil.css" type="text/css">
<title>menues.jsp</title>
</head>

190

<body>
<div class="box1">
<!--Wir fgen das Bild fr unser Content-Management-System ein,
das sich im Ordner web/bilder befindet-->
<img src="../Bilder/oben.jpg" width="800" height="100">
</div>
<div class="variablebox">

11.4 JSP

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

<!--Wir fgen eine Aufzhlung ein und weisen ihr das


CSS-Format list zu -->
<ul class="list">
<!--Wir fgen einzelne Aufzhlungspunkte hinzu, in die
wir Hyperlinks einfgen. Die Hyperlinks haben ebenfalls
das Format list, fr das wir auch Formate fr Hyperlinks
festgelegt haben-->
<li><a href="">Home</a></li>
<li><a href="">Kontakt</a></li>
</ul>
</div>
<div class="box2">
<!--Wir weisen den Hyperlinks das CSS-Format menu zu -->
<span class="menu">
<a href="">Impressum</a>
</span>
</div>
<div class="box3">
<span class="font4">
<br><br>
Willkommen!
</span>
</div>
</body>
</html>
Listing 11.11: menues.jsp

Soweit unser Ausug in die Welt des HTML und der CSS-Formatierungen.

11.4.2 Syntaxelemente in einem JSP


Bis jetzt besteht unser JSP nur aus HTML und CSS, so stellt sich folgende Frage: Wie knnen Sie
in ein JSP Java einbetten? Wir wollen uns im Folgenden auf diese Syntaxelemente konzentrieren:
Direktiven, Deklarationen, Skriptlets und Expressions.

Direktiven
Es gibt drei Arten von Direktiven, und zwar Page, Include und Taglib. Mit Direktiven knnen
Sie in einem JSP allgemeine Informationen festlegen. Lassen Sie uns mit der Page-Direktive und

191

11 Einstieg in J2EE

seinem Attribut Language beginnen. Mit unten stehendem Attribut Language teilen Sie Tomcat
mit, dass Sie im JSP Java als Programmiersprache verwenden.
<%@page

l a n g u a g e =" j a v a " %>

Weitere Attribute der Page-Direktive sind contentType und pageEncoding:


<%@page

c o n t e n t T y p e=" t e x t / h t m l"%>

<%@page

p a g e E n c o d i n g="UTF8"%>

Diese Direktiven ersetzen den HTML-Tag, der als Mime-Type einer HTML-Seite HTML und den
Zeichensatz UTF-8 festlegt.
<meta

h t t p e q u i v ="C o n t e n t Type "

c o n t e n t =" t e x t / h t m l ;

c h a r s e t=UTF8">

Es ist zu empfehlen die JSP-Direktiven anstelle des Meta-Tags zu nehmen, da es ansonsten zu


Problemen, z. B. mit Umlauten kommt, wenn Sie Daten mit POST und GET versenden.
Gibt es weitere Page-Attribute? Ja: import. Mit dem Attribut import knnen Sie in Ihr JSP
Javaklassen importieren.
<%@ p a g e

i m p o r t =" j a v a . u t i l . C o l l e c t i o n ,

K l a s s e n . WebSite " %>

Wollen Sie z.B. Hyperlinks in eine separate Datei namens menue.jsp auslagern und diese Datei
in Ihr JSP einfgen, so brauchen Sie die Direktive Include.
<%@ i n c l u d e

f i l e ="menue . j s p " %>

Unsere letzte Direktive, die Taglib-Direktive, macht es Ihnen mglich in einem JSP sogenannte
Custom Tags zu verwenden, die wir uns weiter unten nher ansehen werden.
<%@ t a g l i b

u r i =" h t t p : / / j a v a . s u n . com/ j s p / j s t l / c o r e "

p r e f i x ="c"%>

Expressions
In einem JSP wird der Befehl print(); ersetzt durch eine Expression. Eine Expression haben wir
bereits kennen gelernt, und zwar die, die den Pfad des Projektes zurckgibt:
<%=r e q u e s t . g e t C o n t e x t P a t h ()%>
In unten stehendem JSP, mit Namen expression.jsp, habe ich Ihnen ein paar Beispiele zusammengestellt, die Ihnen verdeutlichen sollen, dass eine Expression genauso funktioniert wie die
print()-Methode und im Servlet auch in eine solche umgewandelt wird. Das Servlet knnen Sie
einsehen, indem Sie in der Project-Ansicht mit der rechten Maustaste das JSP anklicken und
View Servlet auswhlen.

1
2
3
4
5
6
7
8
9

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>

192

11.4 JSP

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

<title>Expressions</title>
</head>
<body>
<!--wird im Servlet durch folgendes ersetzt
out.print("hallo" );-->
<%="hallo" %>
<br>
<!--wird im Servlet durch folgendes ersetzt:
out.print(request.getContextPath());-->
<%=request.getContextPath()%>
<br>
<!--wird im Servlet durch folgendes ersetzt:
out.print(new java.util.Date() );-->
<%=new java.util.Date() %>
<br>
<!--wird im Servlet durch folgendes ersetzt:
out.print(false );-->
<%=false %>
</body>
</html>

Listing 11.12: Beispiele fr Expressions:expression.jsp

Nachdem Sie das Projekt gestartet haben, erhalten Sie die folgende Ausgabe im Browser:

Abbildung 11.13: Ausgabe von expression.jsp

Merke: Mithilfe einer Expression knnen Sie nur Inhalte von bereits existierenden Methoden und
Variablen im Browser ausgeben. Es knnen keine neue Methoden oder Variablen erstellt werden.
Eine Expression dient nur zur Ausgabe von Daten. Und dieser Inhalt landet beim Umwandeln
eines JSPs in ein Servlet innerhalb der Methode _jspService() des Servlets.

193

11 Einstieg in J2EE

Skriptlets
Skriptlets machen es Ihnen mglich Java in Ihr JSP zu integrieren. So knnen Sie in einem JSP
for-Schleifen erstellen oder lokale Variablen deklarieren.
<% S t r i n g

str

= new

String (" Ich

bin

ein

neues

Skriptlet !");

%>

Skriptlets werden genauso wie Expressions nach dem Umwandeln in ein Servlet Teil der _jspService()Methode des Servlets.

Deklarationen
Wollen Sie Methoden, Klassen- und Instanzvariablen deklarieren, bentigen Sie so genannte
Deklarationen, da diese im Gegensatz zu Skriptlets und Expressions Javacode auerhalb der
Methode _jspService() des Servlets erzeugen.
<%!

String

str

= new

String (" Ich

bin

ein

neues

Skriptlet !");

%>

Ein zusammenfassendes Beispiel


In unten stehendem JSP mit Namen syntaxElemente.jsp werden alle vier Syntaxelemente nochmals mit einem Beispiel verdeutlicht.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

<!--Mit
<%@page
<%@page
<%@page

Direktiven werden allgemeine Informationen im JSP festgelegt-->


language="java" %>
contentType="text/html"%>
pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Syntaxelemente eines JSP</title>
</head>
<body>

194

<!--Mit einer Deklaration koennen Sie Klassen- und


Instanzvariablen erzeugen.-->
<%! String st = new String("Guten Tag");%>
<!--Mit einem Skriptlet koennen Sie lokale Variablen
deklarieren und der entsprechende Code landet in
der _jspService-Methode.-->
<% String s = new String("Hallo");%>
<!--Mit einer Expression koennen Sie Werte von Variablen und
Methoden im Browser ausgeben und der entsprechende Code
landet in der _jspService-Methode.-->
<%=st%>
<br>

11.4 JSP

29
30
31
32

<%=s%>
</body>
</html>
Listing 11.13: syntaxElemente.jsp

Es werden die Werte von beiden Variablen im Browser ausgegeben:

Abbildung 11.14: Ausgabe von syntaxElemente.jsp im Browser

Oben stehendes JSP wird in folgendes Servlet umgewandelt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

package Kap11;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class syntaxElemente_jsp
extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
String st = new String("Hallo");
private static java.util.List _jspx_dependants;
public Object getDependants() {
return _jspx_dependants;
}
public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;

195

11 Einstieg in J2EE

JspWriter out = null;


Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

try {
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request,
response, null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("<!--Mit Direktiven werden allgemeine\n");
out.write("Informationen im JSP festgelegt-->\n");
out.write("\n");
out.write("\n");
out.write("\n");
out.write("\n");
out.write("<!DOCTYPE HTML PUBLIC " +
"\"-//W3C//DTD HTML 4.01 " +
"Transitional//EN\"\n");
out.write("\"http://www.w3.org/TR/html4/loose.dtd\">\n");
out.write("\n");
out.write("<html>\n");
out.write("
<head> \n");
out.write("
<title>Syntaxelemente eines JSP" +
"</title>\n");
out.write("
</head>\n");
out.write("
<body>\n");
out.write("
\n");
out.write("
<!--Mit einer Deklaration knnen" +
" Sie\n");
out.write("
Klassen- und Instanzvariablen " +
"erzeugen-->\n");
out.write("
");
out.write(" \n");
out.write("
\n");
out.write("
<!--Mit einem Skriptlet knnen Sie\n");
out.write("
lokale Variablen erzeugen-->\n");
out.write("
");
String s = new String("Hallo");
out.write("\n");
out.write("
\n");
out.write("
<!--Mit einer Expression knnen " +

196

11.4 JSP

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

"Sie\n");
out.write("
Werte im Browser ausgeben-->\n");
out.write("
");
out.print(s);
out.write("\n");
out.write("
\n");
out.write("
</body>\n");
out.write("</html>\n");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (_jspx_page_context != null) _jspx_page_context.
handlePageException(t);
}
} finally {
if (_jspxFactory != null) _jspxFactory.
releasePageContext(_jspx_page_context);
}

Listing 11.14: syntaxElemente_jsp.java

Verwenden der JSP Standard Tag Library (JSTL)


Das wichtigste Ziel unserer JSP-Datei ist es, mglichst wenig Javaprogrammierzeilen zu enthalten
und die Programmierlogik in das Servlet auszulagern. So sollten in einem JSP nur Daten ein- und
ausgegeben werden. Dies reduziert den Programmieraufwand und erleichtert die Zusammenarbeit
von Programmierern und Webdesignern. Die oben genannten Syntaxelemente erreichen dieses
Ziel nur unzureichend, so wurde zustzlich die JSP Standard Tag Library (JSTL) eingefhrt, die
auch Custom Tags oder Taglibs genannt wird.
Wollen Sie die Custom Tags verwenden, bentigen Sie zwei Bibliotheken, und zwar die jstl.jar
und die standard.jar. Beide Bibliotheken hat NetBeans bereits zu Beginn in das Projekt integriert
und Sie knnen sie in der Project-Ansicht unter Libraries nden. Wollen Sie in Ihrem JSP Taglibs
verwenden, mssen Sie in Ihr Dokument die bereits weiter oben kennen gelernt Taglib-Direktive
schreiben.

Auslesen von Parametern und Attributen


Wie knnen Sie Parameter und Attribute im JSP auslesen? Der Befehl <c:out> entspricht der
print()-Methode, mit ${Formatierung} knnen Sie den Wert eines Attributes und mit ${param.Formatierung} den Wert eines Parameters aus dem Request auslesen. Weiter oben haben
wir ein Servlet und ein JSP (ZweitesServlet.java und zweitesJSP.jsp) erstellt, das zu unten stehendem JSP Daten sendet.

<%@page language="java" %>

197

11 Einstieg in J2EE

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!--Hier legen Sie fest, dass Sie im JSP Taglibs
einsetzen moechten-->
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>drittesJSP.jsp</title>
</head>
<body>
<!--Hier wird der Wert des
Session-Attributes ausgegeben-->
<c:out value="${Formatierung}" />
<br><br>
<!--Hier wird der Wert des
Request-Parameters ausgegeben-->
<c:out value="${param.Formatierung}" />
</body>
</html>
Listing 11.15: drittesJSP.jsp

Auslesen von Daten aus Listen und Maps


Mit dem Tag <c:forEach>-Tag werden Elemente aus einer Liste und einer Map ausgelesen und
<c:forEach> entspricht der for-Schleife in Java. Der Tag besteht aus drei Teilen: dem Anfangstag
<c:forEach>, der Ausgabe und dem Endtag </c:forEach>.
In der Klasse ListenUndMaps.java erstellen wir sowohl eine ArrayList als auch eine HashMap
und fgen jeweils zwei Elemente hinzu, bergeben beide der Session als Attribut und senden
die Daten an das JSP mit Namen ListenUndMaps.jsp weiter. Da Session-Attribute Teile des
Requests sind, also der Anfrage vom Client an den Server, brauchen wir unten stehendes JSP
mit einem Hyperlink, das einen Request erzeugt und diesen an unser Servlet weitersendet.

1
2
3
4
5
6

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<html>
<head>

198

11.4 JSP

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

<title>ausgaben.jsp</title>
</head>
<body>
<!--Der Hyperlink hat das ListenUndMaps-Servlet
mit Namen ListenUndMaps als Ziel. Zusaetzlich wird
mit GET die Variable aus versendet, die den Wert ja
hat. Die Variable aus wird bei GET mit dem ? angehaengt.-->
<a href="<%=request.getContextPath()%>/ListenUndMaps?aus=ja">
Auslesen
</a>
</body>
</html>
Listing 11.16: ausgaben.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

package Kap11;
import
import
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
java.io.IOException;
java.util.ArrayList;
java.util.HashMap;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.ServletException;

public class ListenUndMaps extends HttpServlet {


protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
/*Ist der Wert des Parameters aus ausgaben.jsp nicht leer,
*dann soll der Code innerhalb der if-Struktur
*ausgefhrt werden.*/
if(request.getParameter("aus")!=null){
/*Wir erstellen 2 Formatierungsobjekte.*/
Formatierung f = new Formatierung("font1");
Formatierung fo = new Formatierung("font2");
/*Wir erstellen eine ArrayList.*/
ArrayList<Formatierung> liste = new ArrayList<Formatierung>();

199

11 Einstieg in J2EE

/*Wir fgen der ArrayList 2 Formatierungsobjekte


*hinzu.*/
liste.add(f);
liste.add(fo);

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

/*Wir bergeben die ArrayList der Session als


*Attribut*/
request.getSession().setAttribute("liste", liste);
/*Wir instanziieren eine HashMap()*/
HashMap fehler = new HashMap();
/*Wir fgen der HashMap zwei Elemente hinzu*/
fehler.put("eins", "Hier fehlt etwas!");
fehler.put("zwei", "Hier fehlt noch etwas!");
/*Wir bergeben die HashMap der Session als
*Attribut*/
request.getSession().setAttribute("fehler", fehler);

/*Das Servlet wird zum JSP ListenUndMaps.jsp umgeleitet*/


request.getRequestDispatcher("/Kap11/ListenUndMaps.jsp").
forward(request, response);

protected void doPost(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

Listing 11.17: Erstellen einer Liste und einer Map


Anschlieend lesen wir in unten stehendem JSP mithilfe des Tags <c:forEach> die Elemente der
ArrayList und der HashMap wieder aus. Mit formatierung.name knnen Sie direkt den Namen
eines CSS-Formats auslesen, wobei die Getter-Methode getName() durch name ersetzt wird.
Bei Maps knnen Sie auf das Element selbst mit value, auf den Schlssel mit key und auf ein
bestimmtes Element mit dem Namen des Schlssels zugreifen.

1
2
3
4
5
6
7
8

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

200

11.4 JSP

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

<html>
<head>
<title>ListenUndMaps.jsp</title>
</head>
<body>
<!--forEach liest alle Elemente unserer ArrayList aus-->
<c:forEach var="formatierung" items="${liste}">
<!--mit formatierung.name koennen Sie direkt
auf den Namen der Formatierung zugreifen, es
ersetzt formatierung.getName() -->
<c:out value="${formatierung.name}" />
<!--Endtag nicht vergessen!-->
</c:forEach>
<br>
<!--forEach liest alle Elemente unserer HashMap aus-->
<c:forEach var="fehlerausgabe" items="${fehler}">
<!--mit fehlerausgabe.key wird direkt auf den
Schluessel der Map zugegriffen-->
<c:out value="${fehlerausgabe.key}" />
<br>
<!--mit fehlerausgabe.value wird direkt auf das
Element der Map zugegriffen-->
<c:out value="${fehlerausgabe.value}" />
<br>
<!--Endtag nicht vergessen!-->
</c:forEach>
<br>
<!--Sie koennen auch direkt mithilfe des Schluessels
auf ein bestimmtes Element zugreifen-->
<c:out value="${fehler.eins}" />
</body>
</html>
Listing 11.18: Auslesen der ArrayList und der HashMap im JSP(ListenUndMaps.jsp)

Vergessen Sie nicht, dass das Servlet in die web.xml eingetragen werden muss:

201

11 Einstieg in J2EE

1
2
3
4
5
6
7
8

<servlet>
<servlet-name>ListenUndMaps</servlet-name>
<servlet-class>Kap11.ListenUndMaps</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListenUndMaps</servlet-name>
<url-pattern>/ListenUndMaps</url-pattern>
</servlet-mapping>
Listing 11.19: listenWeb.xml

Starten Sie nun das Projekt, rufen das ausgabe.jsp auf und klicken auf den Hyperlink, so erhalten
Sie folgende Ausgabe im Browser:

Abbildung 11.15: Ausgabe im Browser

Der <c:set>-Tag
Mit dem <c:set>-Tag knnen Attribute gesetzt werden, und zwar fr folgende Geltungsbereiche:
Page, Request, Session und Context/Application. Der Geltungsbereich Page ist der Kleinste,
da das Attribut nur auf dieser Seite gltig ist, in dem das Attribut deniert wurde. Wird kein
Geltungsbereich (scope) festgelegt, gilt automatisch der Geltungsbereich Page, sprich die Variable
ist nur auf dieser Seite gltig.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Variablen und Attribute setzen</title>
</head>
<body>

202

11.4 JSP

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

<c:set var="eins" value="Hallo" />


<c:out value="${eins}"/>
<br>
<c:set var="zwei" scope="session" value="Guten Tag" />
<c:out value="${zwei}"/>
<br>
<c:set var="drei" scope="request" value="Tschuess" />
<c:out value="${drei}"/>
<br>
<c:set var="vier" scope="application" value="Guten Morgen" />
<c:out value="${vier}"/>
</body>
</html>
Listing 11.20: Festlegen der Geltungsbereiche von Attributen in einem JSP (set.jsp)

Sie erhalten im Browser das unten stehende Ergebnis:

Abbildung 11.16: set.jsp

Kontrollstruktur: <c:if>-Tag
Der <c:if>-Tag entspricht der bereits bekannten if-Struktur aus Java, wobei es allerdings keinen
else-Zweig gibt. Sie sind also darauf angewiesen, statt eines else-Zweiges wieder ein <c:if>-Tag
zu verwenden.

1
2
3
4
5
6
7

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

203

11 Einstieg in J2EE

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

<html>
<head>
<title>If-Struktur</title>
</head>
<body>
<c:set var="eins" value="eins" />
<c:set var="zwei" value="zwei" />
<!--Fuer den Fall, dass die Variable eins
existiert, soll der Inhalt der Variablen eins
ausgegeben werden.-->
<c:if test="${eins != null}" >
<c:out value="${eins}"/>
</c:if>
<br>
<!--Fuer den Fall, dass die Variable zwei nicht
existiert, soll der Inhalt der Variablen eins
ausgegeben werden.-->
<c:if test="${zwei == null}" >
<c:out value="${eins}"/>
</c:if>
</body>
</html>

Listing 11.21: kontrollstrukturIf.jsp

Da nur die erste Bedingung zutrit, wird im Browser eins ausgegeben:

Abbildung 11.17: Ausgabe von kontrollstrukturIf.jsp

Merke: Sie bentigen fr die Kontrollstruktur sowohl den Anfangstag <c:if> als auch den Endtag
</c:if>.

204

11.4 JSP

Kontrollstruktur: <c:choose>-Tag
Gibt es auch eine switch-Struktur in den Taglibs? Ja! Das <c:choose>-Tag mit den Fllen
<c:choose> und dem Default-Fall <c:otherwise>. Der <c:choose>-Tag unterscheidet sich allerdings geringfgig von der gewohnten Vorgehensweise in Java. Es wird immer nur ein Fall
des <c:choose>-Tag ausgefhrt, und zwar der erste Fall <c:when>, auf den true zutrit, auch
wenn mehrere zutreen. Ein break, wie es in der switch-Struktur unbedingt erforderlich ist, um
nur einen Fall ausfhren zu lassen, ist bei der Kontrollstruktur <c:choose> nicht notwendig.
Trit kein Fall zu, wird der Default-Fall, <c:otherwise> durchgefhrt. In der Kontrollstruktur
<c:choose> kann der Tag <c:otherwise> weggelassen werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Choose-Struktur</title>
</head>
<body>
<c:set var="eins" value="Sonnenschein" />
<c:set var="zwei" value="Regen" />
<c:choose>
<c:when test="${eins != null}" >
<c:out value="${eins}"/>
</c:when>
<c:when test="${zwei != null}" >
<c:out value="${zwei}"/>
</c:when>
<c:otherwise>
Ich bin der Standardfall
</c:otherwise>
</c:choose>
</body>
</html>
Listing 11.22: kontrollstrukturChoose.jsp

205

11 Einstieg in J2EE

Es treen zwar beide Flle zu, aber nur der erste zutreende Fall wird tatschlich abgearbeitet:

Abbildung 11.18: Ausgabe von kontrollstrukturChoose.jsp

11.5 Filter
Was ist ein Filter? Ein Filter steht innerhalb der Verarbeitungskette zwischen Client und Server.
Sendet ein Client eine Anfrage an den Server oder sendet ein Server eine Antwort an den Client
wird der Filter vorher ausgefhrt. Wobei sich allerdings die Methoden des Requests und des
Responses erheblich unterscheiden. Sie knnen nur aus dem Request Parameter auslesen und
Attribute setzen. Welche Aufgaben kann ein Filter innerhalb einer Webapplikation bernehmen?
Es sind u.a. die Folgenden:
1. Beim Login kann das Passwort berprft werden.
2. Es kann berprft werden, ob eine Session noch gltig ist.
3. Es knnen Benutzerbewegungen protokolliert werden.
4. Es knnen Daten aktualisiert werden.
Kehren wir zu unserem Content-Management-System zurck: Hier soll unten stehender FormatierungsFilter.java folgende Aufgaben bernehmen: Erstens soll er jedes Mal wenn Daten hinzugefgt oder gelscht werden, alle Daten in den JSP-Seiten auf den neuesten Stand bringen.
Und zweitens soll er uns Daten zur Verfgung stellen, wenn die Webseite zum ersten Mal durch
den Client aufgerufen wird. Warum gibt es keine Daten aus der Datenbank, wenn die Webseite
zum ersten Mal aufgerufen wird? Wir erinnern uns, Attribute und Parameter, die in einem JSP
ausgelesen werden, werden aus dem Request ausgelesen. Ein Request besteht aber erst ab dem
Zeitpunkt, an dem der Client eine Anfrage zum Server schickt und dies ist bei erstmaligem Aufruf
nicht der Fall, da es zu diesem Zeitpunkt nur eine Antwort gibt, also einen Response, vom Server
zum Client gesendet und keinen Request.
Wie erstellen wir einen Filter? Ein Filter wird erstellt, indem Sie das Interface Filter und seine drei
Methoden implementieren. Die Methoden init(), doFilter() und destroy() stellen Anfangspunkt,
Leben und Endpunkt eines Filters dar.

1
2
3
4
5
6
7
8

package Eingang;
import
import
import
import
import
import

206

Datenbankabfragen.FormatierungDaten;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
java.io.IOException;
java.util.ArrayList;
javax.servlet.Filter;

11.5 Filter

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

import
import
import
import
import
import
import
import

javax.servlet.FilterChain;
javax.servlet.FilterConfig;
javax.servlet.ServletException;
javax.servlet.ServletRequest;
javax.servlet.ServletResponse;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.http.HttpServletResponseWrapper;

public class FormatierungFilter implements Filter {


private FilterConfig filterConfig = null;
/*Die init()-Methode wird bei der Instanziierung des
Filters aufgerufen und es wird ber das FilterConfig und
die Methode getServletContext() einen Zugriff auf
den ServletContext ermglicht.*/
public void init(FilterConfig filterConfig) throws
ServletException {
this.filterConfig = filterConfig;
}
/*In der doFilter()-Methode werden die Aufgaben
des Filters durchgefhrt.*/
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
/*Das ServletRequest request muss in ein
HttpServletRequest gecastet werden, da
es sich um eine Webanwendung handelt*/
HttpServletRequest req = (HttpServletRequest) request;
/*Das Attribut formatierung soll aus der Session
entfernt werden*/
req.getSession().removeAttribute("formatierung");
/*Wir lesen alle Formatierungsobjekte aus der
Datenbank aus. Da wir im Projekt mit dem
Embedded-Modus arbeiten, mssen wir der Methode auslesen
zustzlich ein Objekt der Klasse HttpServletRequest req
bergeben*/
FormatierungDaten format = new FormatierungDaten();
ArrayList<Formatierung> formatierung = format.auslesen(req);
/*Wir bergeben die soeben ausgelesene ArrayList der

207

11 Einstieg in J2EE

Session als Attribut*/


req.getSession().setAttribute("formatierung", formatierung);

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

/*Mit der Ausgabe auf der Konsole knnen Sie berprfen, ob


der Filter durchgefhrt wurde*/
System.out.println("aktuelle Daten");
/*Der Request und der Response wird der FilterChain
bergeben, sprich gibt es mehrere Filter, werden diese
jetzt in der Reihenfolge, wie sie in der web.xml stehen,
abgearbeitet*/
chain.doFilter(request, response);
}
/*Diese Methode wird als letztes aufgerufen bevor der Server
geschlossen wird und Sie knnen in dieser Methode
gegebenenfalls Ressourcen freigeben*/
public void destroy() {
}

Listing 11.23: FormatierungFilter.java


Filter mssen genau wie Servlets in die web.xml eingetragen werden, da ihm spezielle Funktionen
zufallen und dies Tomcat mitgeteilt werden muss. Im Filter-Mapping knnen Sie festlegen, ob
der Filter immer ausgefhrt wird, oder nur bei bestimmten Servlets. In unserem Projekt ist
es sinnvoll, den Filter FormatierungFilter.java nur bei einem bestimmten Servlet ablaufen zu
lassen, da es nicht zweckmig ist, bei jeder x-beliebigen Abfrage die Formatierungsobjekte zu
aktualisieren und auf diesem Weg, die Datenbank ber Gebhr in Anspruch zu nehmen.
Gibt es mehrere Filter werden Sie in der Reihenfolge, in der Sie in der web.xml stehen, abgearbeitet. Dies ist die so genannte FilterChain. Wobei Sie allerdings beachten sollten, dass fr
den Response und den Request im Filter unterschiedliche Methoden zur Verfgung stehen. Sie
knnen nur aus dem Request Parameter auslesen und Attribute setzen. Wenn Sie also die Daten
des Request weiterleiten wollen, knnen Sie dies mit FORWARD des RequestDispatchers tun.
Dies mssen Sie im <dispatcher>-Element des Filter-Mappings separat festlegen. Das gleiche
gilt fr die Flle Include und ErrorPage.

1
2
3
4
5
6
7
8
9
10

<?xml version="1.0" encoding="UTF-8"?>


<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

208

<filter>
<!-- Name des Filters -->
<filter-name>FormatierungFilter</filter-name>

11.5 Filter

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

<!-- Ort, an dem der Filter gespeichert wurde -->


<filter-class>Eingang.FormatierungFilter</filter-class>
</filter>
<filter-mapping>
<!-- Name des Filters -->
<filter-name>FormatierungFilter</filter-name>
<!-- Filter wird immer ausgefuehrt -->
<url-pattern>/*</url-pattern>
<!-- oder Filter wird bei folgendem Servlet ausgefuehrt:
<servlet-name>BestimmtesServlet</servlet-name>-->
<!-- Filter wird ausgefuehrt, wenn ein Request mit
dem RequestDispatcher weitergeleitet wurde-->
<dispatcher>FORWARD</dispatcher>
<!-- Filter wird bei einem Request ausgefuehrt, dies
ist der Standard, fuer den Fall, dass keine dispatcherElemente festgelegt wurden-->
<dispatcher>REQUEST</dispatcher>
<!-- Filter wird ausgefuehrt, wenn eine Datei
mit inlude eingebunden wurde-->
<dispatcher>INCLUDE</dispatcher>
<!-- Filter wird im Zusammenhang mit einer ErrorPage
ausgefuehrt -->
<dispatcher>ERROR</dispatcher>
</filter-mapping>
</web-app>
Listing 11.24: Filter-Mapping in der web.xml (formatierungWeb.xml)

Wollen Sie einen Filter erstellen, der ausgefhrt wird, wenn Daten vom Server zum Client gesendet werden, knnen Sie nur auf Methoden des Response zurckgreifen. Sie bentigen wie oben
beim Servlet wieder ein PrintWriter-Objekt, das es Ihnen ermglicht, Daten in einen Puer und
anschlieend in die HTML-Datei zu schreiben.

1
2
3
4

package Kap11;
import java.io.IOException;
import java.io.PrintWriter;

209

11 Einstieg in J2EE

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

import
import
import
import
import
import
import
import
import
import

java.util.ArrayList;
javax.servlet.Filter;
javax.servlet.FilterChain;
javax.servlet.FilterConfig;
javax.servlet.ServletException;
javax.servlet.ServletRequest;
javax.servlet.ServletResponse;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.http.HttpServletResponseWrapper;

public class PrintWriterFilter implements Filter {

210

private FilterConfig filterConfig = null;


public void init(FilterConfig filterConfig)
throws ServletException {
}

this.filterConfig = filterConfig;

public void doFilter(ServletRequest request,


ServletResponse response, FilterChain chain)
throws IOException, ServletException {
/*Das Objekt ServletResponse response muss in ein
HttpServletResponse-Objekt gecastet werden, da
es sich um eine Webanwendung handelt*/
HttpServletResponse res = (HttpServletResponse)response;
res.setContentType("text/html");
/*Sie brauchen wieder - wie beim Servlet - das PrintWriter-Objekt
um zu dem Response Daten hinzufgen zu knnen*/
PrintWriter out = res.getWriter();
out.println("<html>");
out.println(" <head>");
out.println("
<title>HelloWorld</title>");
out.println(" </head>");
out.println(" <body>");
out.println("
Hello World");
out.println(" </body>");
out.println("</html>");
}

chain.doFilter(request, response);

11.6 Deployment Descriptor: web.xml

54
55
56
57
58

public void destroy() {


}
}
Listing 11.25: PrintWriterFilter.java

11.6 Deployment Descriptor: web.xml


Der Deployment Descriptor, die web.xml, beschreibt fr den Webserver die Aufgabenteilung
verschiedener Teile der Webapplikation und legt Parameter fest. Wie wir auf den vergangenen
Seiten gesehen haben, mssen Servlets und Filter eingetragen werden, und es kann die Dauer einer
Session bestimmt werden. Was wir noch nicht gesehen haben: Wie legen wir Parameter in der
web.xml fest und welche Parameter gibt es? Es gibt zweierlei Parameter: den Servlet-Parameter
und den Context-Parameter. Der Servlet-Parameter steht Ihnen fr ein bestimmtes Servlet zur
Verfgung und wird innerhalb des Servlet Tags festgelegt. Wohingegen der Context-Parameter
einen greren Geltungsbereich besitzt, Sie knnen innerhalb des gesamten Projektes auf diesen
Parameter zugreifen. Sie legen einmal z.B. eine E-Mail-Adresse an, dann steht Sie Ihnen in der
gesamten Webapplikation zur Verfgung. Sollte sich Ihre E-Mail-Adresse ndern, mssen Sie sie
nur noch an einer Stelle ndern.
Parameter des Contexts und des Servlets knnen mit der getInitParameter()-Methode abgefragt
werden. Auf den Context-Parameter knnen Sie nur zugreifen, wenn Sie sich vorher Zugri auf
den Context verschaen:
getServletContext ( ) . getInitParameter (" email ")
Wollen Sie den Parameter des Servlets abfragen, mssen Sie zuerst die Methode getServletCong() ausfhren:
g e t S e r v l e t C o n f i g ( ) . getInitParameter (" email ")
Wie legen wir Servlet-Parameter und Context-Parameter an? In der web.xml erstellen wir fr
den Context-Parameter ein <context-param>-Element und fr den Servlet-Parameter innerhalb
des <servlet>-Element ein <init-param>-Element.

1
2
3
4
5
6
7
8
9
10
11
12
13

<?xml version="1.0" encoding="UTF-8"?>


<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- Folgender Parameter gilt fuer die ganze Webapplikation: -->
<context-param>
<param-name>Leiter</param-name>
<param-value>Herr Markus Muster</param-value>
</context-param>
<servlet>

211

11 Einstieg in J2EE

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

<servlet-name>InitParameter</servlet-name>
<servlet-class>Kap11.InitParameter</servlet-class>
<!-- Folgender Parameter gilt fuer das Servlet InitParameter: -->
<init-param>
<param-name>Mail</param-name>
<param-value>markus@muster.de</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>InitParameter</servlet-name>
<url-pattern>/InitParameter</url-pattern>
</servlet-mapping>
</web-app>

Listing 11.26: initParameterWeb.xml

Erstellen wir ein Servlet mit Namen InitParameter.java und greifen auf die Parameter mit den
entsprechenden Methoden zu, gibt Tomcat folgendes auf der Konsole aus:

Abbildung 11.19: Ausgabe des Context-Parameters und des Servlet-Parameters

Wohingegen Sie im JSP nur auf den Context-Parameter zugreifen knnen. Und fr den ServletParameter wird null ausgegeben:

212

11.6 Deployment Descriptor: web.xml

Abbildung 11.20: Ausgabe im Browser des InitParamer.jsp

Das zugehrige JSP sieht wie folgt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>InitParameter.jsp</title>
</head>
<body>
<%
/*Sie koennen nicht auf den Parameter Mail
zugreifen, da er nur fuer das Servlet
InitParamter.java gueltig ist.*/
ServletConfig sc = getServletConfig();
String s = sc.getInitParameter("Mail");
/*Aber das JSP kann auf den Context-Parameter
zugreifen.*/
ServletContext scon = getServletContext();
String st = scon.getInitParameter("Leiter");
%>
Servlet-Parameter:
<br>
<%=s%>
<br><br>
Context-Parameter:
<br>
<%=st%>

213

11 Einstieg in J2EE

</body>
</html>

37
38

Listing 11.27: initParameter.jsp

11.7 Listener
Wollen Sie wissen, wann eine Session oder ein Request beginnt? Oder: Interessiert es Sie, wann der
Session Attribute hinzugefgt werden? Dann brauchen Sie einen Listener. Ein Listener hrt auf
alle Ereignisse Ihrer Applikation und ist in der Lage, sie aufzuzeichnen oder sie zu beeinussen.
Also: Immer wenn irgendetwas Interessantes in Ihrer Web-Applikation passiert, der Listener ist
dabei.

11.7.1 HttpSessionAttributeListener
Mit dem HTTPSessionAttributeListener knnen Sie beobachten, wann Attribute der Session
hinzugefgt oder aus ihr wieder entfernt werden. Wie wird ein solcher Listener erstellt? Als
Erstes brauchen wir einen Eintrag in der web.xml:

1
2
3
4
5

<listener>
<listener-class>
Listeners.MyHttpSessionAttributeListener
</listener-class>
</listener>
Listing 11.28: webListener.xml

Als Nchstes erstellen wir einen Listener mit Namen MyHttpAttributeListener, der das Interface
HttpSessionAttributeListener und seine Methoden implementiert. Diesen Methoden wird als Parameter ein Event bergeben: das so genannte HttpSessionBindingEvent. Dieses Event macht es
Ihnen mglich, die Session-ID, die dazugehrigen Attribute und deren Aktionen auszulesen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package Listeners;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
public class MyHttpSessionAttributeListener implements
HttpSessionAttributeListener {

214

/*Es werden alle Attribute beobachtet, die der Session hinzugefgt


werden.*/
public void attributeAdded(HttpSessionBindingEvent event) {
/*Mit getSession().getId() wird die entsprechend ID der
Session ausgelesen. */

11.7 Listener

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

System.out.println("HttpSessionAttribute sessionId=" +
event.getSession().getId());
/*Es wird der Name des Session-Attributs ausgelesen.*/
System.out.println("HttpSessionAttribute added: name=" +
event.getName() );
/*Es wird der Wert des Session-Attributes ausgelesen.*/
System.out.println("value=" +event.getValue());
}
/*Es werden die gelschten Attribute beobachtet.*/
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("HttpSessionAttribute removed: name:"
+event.getName());
System.out.println("value=" +event.getValue());
}
/*Es werden die ersetzten Session-Attribute beobachtet.*/
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println("HttpSessionAttribute replaced: name:"
+event.getName());
System.out.println("value=" +event.getValue());
}
}

Listing 11.29: MyHttpSessionAttributeListener.java

Die unten stehende Ausgabe erhalten Sie, wenn Sie unser Projekt (vgl. Kapitel Unser ContentManagement-System) mit einer gefllten Datenbank starten und auf einen Hyperlink klicken:
HttpSessionAttribute removed: name:webSiteMenu
value=[Datenbankentwurf.Link@1cfa965, Datenbankentwurf.Link@1843ca4]
HttpSessionAttribute replaced: name:webSiteTextFormatierung
value=[Datenbankentwurf.Formatierung@476914]
HttpSessionAttribute replaced: name:webSiteBild
value=[Datenbankentwurf.Bild@197871d]
HttpSessionAttribute replaced: name:webSitePdf
value=[Datenbankentwurf.PDF@187b5 ]
HttpSessionAttribute sessionId=9D0028D256C5B321F2CF7F317B4A4B83
HttpSessionAttribute added: name=webSiteMenu
value=[Datenbankentwurf.Link@d0005e, Datenbankentwurf.Link@18a270a]
HttpSessionAttribute removed: name:ListLink

215

11 Einstieg in J2EE

11.7.2 ServletContextListener
Was macht ein ServletContextListener? Er kann den Anfang und das Ende des Servlet-Contexts
im Auge behalten. Auerdem ist seine Methode contextInitialized() die erste Methode, die durchgefhrt wird, wenn die Web-Applikation gestartet wird. So kann der ServletContextListener dazu
verwendet werden, eine Datenbank zu nen und wieder zu schlieen.
Wie wird ein ServletContextListener erzeugt? Sie erstellen eine Klasse, die den ServletContextListener und seine Methoden contextInitalized() und contextDestroyed() implementieren. Ihnen
wird ein ServletContextEvent als Parameter bergeben. In der Methode contextInitialized() kann
die Datenbank genet werden und in der Methode contextInitialzed() wieder geschlossen werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

package Listeners;
import javax.servlet.*;
public class MyServletContextListener
implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
/*Hier wird die Datenbank geffnet.*/
}
public void contextDestroyed(ServletContextEvent event) {
/*Hier wird die Datenbank geschlossen.*/
}
}
Listing 11.30: MyServletContextListener.java

Der entsprechende Eintrag fr diesen Listener in der web.xml lautet wie folgt:

1
2
3
4
5

<listener>
<listener-class>
Listeners.MyServletContextListener
</listener-class>
</listener>
Listing 11.31: webMyContextListener.xml

Weiter unten in einem separaten Kapitel werden wir sehen, wie wir in einem ServletContextListener den db4o-Server nen knnen.

11.7.3 HttpSessionListener
Wollen Sie wissen, wann eine Session beginnt und wann sie wieder aufhrt? Dann brauchen Sie
die Methoden sessionCreated() und sessionDestroyed() des HttpSessionListener und das HttpSessionEvent.

216

11.7 Listener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

package Listeners;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener {
/*Diese Methode wird gestartet, wenn eine Session beginnt.*/
public void sessionCreated(HttpSessionEvent event) {
System.out.println("sessionCreated : sessionId="
+ event.getSession().getId());
}
/*Diese Methode wird gestartet, wenn eine Session beendet wird.*/
public void sessionDestroyed(HttpSessionEvent event) {
System.out.println("sessionDestroyed : sessionId="
+ event.getSession().getId());
}
}
Listing 11.32: MyHttpSessionListener.java

Mit oben stehendem HttpSessionListener erhalten Sie folgende Ausgabe:


sessionCreated : sessionId=7A163058060BE2B3F436027A4765B451
sessionDestroyed : sessionId=7A163058060BE2B3F436027A4765B451
Und der entsprechende Eintrag fr den HttpSessionListener in die web.xml lautet wie folgt:

1
2
3
4
5
6

<listener>
<listener-class>
Listeners.MyHttpSessionListener
</listener-class>
</listener>

Listing 11.33: mySessionWeb.xml

11.7.4 Weitere Listener


Insgesamt gibt es acht Listener, drei haben wir bereits kennen gelernt und die Restlichen mchte ich Ihnen jetzt kurz vorstellen. Die Listener lassen sich unterscheiden in Context-Listener,
Request-Listener und Session-Listener. Sie beobachten jeweils einen bestimmten Bereich: ContextListener beobachten, alle Vorgnge, die sich auf das ganze Web-Projekt beziehen. Session-Listeners
nehmen alles rund um die Session wahr und die Request-Listener alles in Bezug auf die Requests.

217

11 Einstieg in J2EE

Session-Listener:
1.

HttpSessionBindingListener:

Er behlt alle Attribute, die an die Session gebunden

sind, im Auge. Das entsprechende Event heit HttpSessionBindingEvent und die Methoden
valueBound() and valueUnbound().
2.

HttpSessionActivationListener: Wenn ein Objekt von einer Virtual-Machine zur Nchsten wandert, knnen Sie dies mit den Methoden sessionDidActivate() und sessionWillPassivate() und dem HttpSessionEvent beobachten.

Context-Listener:
1.

ServletContextAttributeListener: Dieser Listener hrt darauf, ob dem Context Attribute hinzugefgt oder aus dem Context gelscht oder ersetzt worden sind. Er funktioniert
analog zum HttpSessionAttributeListener, der uns bereits oben begegnet ist. Sie mssen
drei Methoden implementieren: attributeAdded(), attributeRemoved() und attributeReplaced(), denen Sie jeweils als Parameter das ServletContextAttributeEvent bergeben
mssen.

Request-Listener:
1.

HttpRequestAttributeListener:

Von diesem Listener werden die Attribute des Re-

quests beobachtet. Es besitzt die gleichen Methoden wie der ServletContextAttributeListener, wobei allerdings das bergebene Event anders heit, nmlich ServletRequestAttributeEvent.
2.

ServletRequestListener: Die Methoden requestInitialized() und requestDestroyed() und


das ServletRequestEvent registrieren, wann ein Request beim Server eingeht.

218

12 Embedded-Modus in einem Web-Projekt


Im Kapitel Client-Server-Modus haben wir gelernt, dass der Embedded-Modus der richtige Modus fr Client-Server-Abfragen in einem Web-Projekt ist. So stellt sich die Frage: Wie integrieren wir den Embedded Modus von db4o in unser Web-Projekt? Wir nen in einem speziellen
ServletContextListener den db4o-Server und in einem HttpSessionListener den Client. So besteht whrend einer Session eine Verbindung zwischen Client und Server und wir knnen den
Arbeitspeicher von db4o in unser Content-Management-System integrieren und seine Vorteile
nutzen.
Den Db4oServletContextListener habe ich dem db4o-Tutorial entnommen und geringfgig verndert. Bevor wir den ContextListener erstellen, tragen wir den Namen unserer Datenbank in
die web.xml als Context-Parameter ein. Sie knnen auf einen Context-Parameter von berall,
innerhalb eines Web-Projektes zugreifen. ndern Sie den Namen der Datenbank, so mssen Sie
dies nur noch an dieser Stelle tun.

1
2
3
4

<context-param>
<param-name>db4oFileName</param-name>
<param-value>C:/Datenbank/DasErsteProjekt/datenbank.yap</param-value>
</context-param>
Listing 12.1: contextElement.xml

Als Nchstes erstellen wir fr unseren Db4oServletContextListener einen Eintrag in die web.xml:

1
2
3
4
5

<listener>
<listener-class>
Listeners.Db4oServletContextListener
</listener-class>
</listener>
Listing 12.2: webdb4oListener.xml

Unten stehend der Db4oServletContextListener, der beim Starten eines Web-Projektes mit F6
den db4o-Server startet. Der Server wird dem Context mit dem Namen db4oServer als Attribut
bergeben.

1
2
3
4
5
6
7

package Listeners;
import com.db4o.Db4o;
import com.db4o.ObjectServer;
import javax.servlet.*;
public class Db4oServletContextListener implements ServletContextListener {

219

12 Embedded-Modus in einem Web-Projekt

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

private ObjectServer server = null;


/*Wird das Web-Projekt gestartet, wird folgende Methode
durchgefhrt*/
public void contextInitialized(ServletContextEvent event) {
close();
/*Sie verschaffen sich Zugriff auf den ServletContext.*/
ServletContext context = event.getServletContext();
/*Wir starten den Server und geben einem User Zugriff auf
die Datenbank. Mit getInitParameter greifen Sie
auf den Namen der Datenbank, der als Context-Parameter
hinterlegt wurde, zu.*/
server = Db4o.openServer(context.getInitParameter("db4oFileName"), 0);
/*Wir bergeben dem Context den Server als Attribut.*/
context.setAttribute("db4oServer", server);
/*Es wird eine Meldung ausgegeben, wenn der Server startet.*/
context.log("db4o startup on " +
context.getInitParameter("db4oFileName"));
}
/*Wird das Web-Projekt beendet, wird folgende Methode
durchgefhrt*/
public void contextDestroyed(ServletContextEvent event) {
ServletContext context = event.getServletContext();
/*Das Attribut wird wieder aus dem Context gelscht.*/
context.removeAttribute("db4oServer");
/*Der Server wird geschlossen.*/
close();
context.log("db4o shutdown");
}
private void close() {
if (server != null) {
server.close();
}
server = null;
}
}
Listing 12.3: Db4oServletContextListener.java

220

Ausgabe in Tomcat
11.07.2007 18:33:55 org.apache.catalina.core.ApplicationContext log
INFO: db4o shutdown
11.07.2007 18:33:57 org.apache.catalina.core.ApplicationContext log
INFO: db4o startup on C:\Datenbank\DasErsteProjekt\datenbank.yap
Der Server ist genet und wartet auf Anfragen. Jetzt brauchen wir nur noch einen Client und
den nen wir in einem HttpSessionListener. Warum machen wir dies? Wir wollen zustzlich
den Cache nutzen, den uns db4o zur Verfgung stellt. Im Embedded Modus stellt db4o einen
Arbeitsspeicher zur Verfgung, der es mglich macht, mit gecachten Objekten zu arbeiten. Dies
entlastet die Datenbank, da nicht jede Abfrage auf die Datenbank direkt zugreift, sondern nur
auf die sich im Arbeitsspeicher bendlichen Objekte. So ist es mglich, einer greren Anzahl
Benutzer gleichzeitig Zugri zu gewhren. Sollten Sie aber sofort mit Daten arbeiten wollen,
die durch andere Benutzer eingegeben worden sind, mssen Sie die ausgelesenen Daten vorher
aktualisieren. Hierzu lernen wir am Ende des Kapitels die Methode refresh() kennen.
Jedes Mal, wenn der Benutzer eine Session startet, wird ein Datenbankclient von db4o genet.
Wird die Session wieder beendet, wird auch der Datenbankclient wieder geschlossen. Der Client
bleibt also so lange genet, wie die Session existiert.
Mit der Befehlszeile
( ObjectServer ) event . g e t S e s s i o n ( ) . getServletContext ( )
. g etAtt ribute (" db4oServer ")
knnen Sie auf das Context-Attribut zugreifen, das den Server beinhaltet. Der Server wurde im
Db4oServletContextListener dem Context-Attribut mit Namen db4oServer bergeben und kann
nun wieder ausgelesen werden.
Haben Sie den Bezug auf den Server aus dem Context ausgelesen, knnen Sie die Methode
openClient() ausfhren und Sie erhalten den ObjectContainer, also unseren Client, zurck.
( ( ObjectServer ) event . g e t S e s s i o n ( ) . getServletContext ( )
. g etAtt ribute (" db4oServer " ) . openClient ( ) ;
Der Client wird der Session als Attribut bergeben und erhlt den Namen db4oClient:
event . g e t S e s s i o n ( ) . s e t A t t r i b u t e (" db4oClient " ,

oc ) ;

Unten stehend nden Sie den entsprechenden HttpSessionListener:

1
2
3
4
5
6
7
8
9
10
11
12

package Listeners;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import com.db4o.ObjectContainer;
import com.db4o.ObjectServer;
public class Db4oSessionListener implements
HttpSessionListener {

221

12 Embedded-Modus in einem Web-Projekt

/*Diese Methode wird am Anfang einer Session durchgefhrt*/


public void sessionCreated(HttpSessionEvent event) {

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

/*Der Client des Embedded Modus wird geffnet*/


ObjectContainer oc = ((ObjectServer) event.getSession()
.getServletContext().getAttribute("db4oServer")).openClient();
/*und der Session als Attribut db4oClient bergeben.*/
event.getSession().setAttribute("db4oClient", oc);
}
/*Diese Methode wird durchgefhrt, wenn die Session beendet
wird.*/
public void sessionDestroyed(HttpSessionEvent event) {
/*Am Ende der Session wird der Client geschlossen.*/
((ObjectServer) event.getSession()
.getServletContext().getAttribute("db4oServer")).close();
}
}
Listing 12.4: Db4oSessionListener.java
Der Listener muss in der web.xml registriert werden:

1
2
3
4
5

<listener>
<listener-class>
Listeners.Db4oSessionListener
</listener-class>
</listener>
Listing 12.5: sessionWeb.xml

Im Db4oSessionListener wurde der Client fr eine Session genet, so knnen Sie jetzt in einer
Abfrage, den ObjectContainer, also den Client, aus dem Request und der Session auslesen:
c l i e n t =( O b j e c t C o n t a i n e r ) r e q u e s t . g e t S e s s i o n ( )
. getAttribute (" db4oClient " ) ;
Lassen Sie uns dies anhand einer Beispielabfrage tun: Die vollstndige Methode auslesenLink()
nden Sie in der Klasse AuslesenClient.java. Sie mssen der Methode auslesenLink() ein Objekt
der Klasse HttpServletRequest bergeben, da Sie in einer normalen Klasse nicht auf den Request
zugreifen knnen. Auf ein Objekt der Klasse HttpServletRequest knnen Sie nur innerhalb von
Servlets und Filter zugreifen. Sie bentigen aber ein Objekt der Klasse HttpServletRequest, da
Sie nur so in der Lage sind, ein Session-Attribut auszulesen.

222

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

package Kap12;
import
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectServer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.io.IOException;
java.util.ArrayList;
javax.servlet.ServletContext;
javax.servlet.http.HttpServletRequest;

public class AuslesenClient {


public ArrayList<Link> auslesenLink(HttpServletRequest request){
ObjectContainer client = null;
ArrayList<Link> f = new ArrayList<Link>();
try{
/*Aus dem HttpServletRequest request knnen Sie den
ObjectContainer auslesen.*/
client = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
Link l = new Link(null);
ObjectSet<Link> result = client.get(l);
while (result.hasNext()){
l = result.next();
f.add(l);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return f;
}
}
Listing 12.6: AuslesenClient.java

Nachdem wir den Embedded-Modus eingerichtet haben, lassen Sie uns die Daten mithilfe eines
Filters und eines JSPs im Browser ausgeben. Im Filter werden die Daten mit unserer Methode
auslesenLink() ausgelesen:

223

12 Embedded-Modus in einem Web-Projekt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

package Eingang;
import
import
import
import
import
import
import
import
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Link;
Kap12.AuslesenClient;
com.db4o.ObjectContainer;
java.io.IOException;
java.util.ArrayList;
javax.servlet.Filter;
javax.servlet.FilterChain;
javax.servlet.FilterConfig;
javax.servlet.ServletContext;
javax.servlet.ServletException;
javax.servlet.ServletRequest;
javax.servlet.ServletResponse;
javax.servlet.http.HttpServletRequest;

public class ServerClientFilter implements Filter {


private FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
req.getSession().removeAttribute("ListLink");
AuslesenClient a = new AuslesenClient();
ArrayList<Link> ListLink = a.auslesenLink(req);
req.getSession().setAttribute("ListLink", ListLink);
chain.doFilter(request, response);
}
public void destroy() {
}
}
Listing 12.7: ServerClientFilter.java

Vergessen Sie bitte nicht den Filter in die web.xml einzutragen:

<filter>

224

2
3
4
5
6
7
8

<filter-name>ServerClientFilter</filter-name>
<filter-class>Eingang.ServerClientFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ServerClientFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Listing 12.8: webServerClient.xml

Starten wir nun das Projekt mit F6 und nen das serverClientJSP.jsp,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>Client-Server</title>
</head>
<body>
<c:forEach var="ListLink" items="${ListLink}">
<c:out value="${ListLink.name}" />
</c:forEach>
</body>
</html>
Listing 12.9: serverClientJSP.jsp

erhalten wir folgende Ausgabe im Browser:

Abbildung 12.1: Ausgabe des serverClientJSP.jsp im Browser

225

12 Embedded-Modus in einem Web-Projekt

Diese Ausgabe setzt voraus, dass Sie vorher die Datenbank gelscht und mit den folgenden
Klassen eine Neue erstellt haben: FormatierungOhneTextInDatenbank.java, WebSiteEinlesenInDatenbank.java und WebSiteEinlesenWeitere.java.
Wie Sie gesehen haben, erfordert das Implementieren des Embedded-Modus von db4o in einem
Web-Projekt nur wenige Schritte: Sie mssen die Datenbank als Context-Parameter anlegen,
anschlieend nen Sie den Server in einem ServletContextListener und den Client in einem
HttpSessionListener. So einfach! Und schon haben wir alle Voraussetzungen fr unser ContentManagement-System geschaen, das wir im Kapitel Unser Content-Management-System ausfhrlich besprechen werden.

12.1 Die Methode refresh()


Werden Daten durch andere Benutzer eingegeben, werden die Daten beim Auslesen nicht automatisch aktualisiert. Wollen Sie also wissen, welche Daten durch andere Benutzer eingegeben
worden sind, mssen Sie, die ausgelesenen Daten mit der Methode refresh() auf den neuesten
Stand bringen.
Die Methode refresh() bendet sich im Interface ExtObjectContainer im Package com.db4o.ext.
Sie mssen der Methode refresh() zwei Parameter bergeben, der Erste ist ein Objekt und der
Zweite ist die Suchtiefe. In unserem Fall ist das Objekt der Link link, der aus der Datenbank
ausgelesen worden ist. Die vollstndige Befehlszeile lautet:
c l i e n t . ext ( ) . r e f r e s h ( link ,

I n t e g e r .MAX_VALUE) ;

In unten stehender Klasse AuslesenRefreshClient.java wird diese Zeile eingefgt, nachdem die
Daten ausgelesen wurden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

package Kap12;
import
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectServer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.io.IOException;
java.util.ArrayList;
javax.servlet.ServletContext;
javax.servlet.http.HttpServletRequest;

public class AuslesenRefreshClient {

226

public ArrayList<Link> auslesenLink(HttpServletRequest request){


ObjectContainer client = null;
ArrayList<Link> f = new ArrayList<Link>();
try{
client = (ObjectContainer)request.getSession().

12.2 Update-Tiefe im Embedded Modus

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

getAttribute("db4oClient");
Link link = new Link(null);
ObjectSet<Link> result = client.get(link);
while (result.hasNext()){
link = result.next();
/*Wurden durch einen anderen Benutzer Daten
eingegeben, soll der Cache des aktuellen Benutzers
auf den neuesten Stand der Datenbank gebracht werden.*/
client.ext().refresh(link, Integer.MAX_VALUE);
f.add(link);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return f;
}
}
Listing 12.10: AuslesenRefreshClient.java

Sollten die Daten in der Datenbank nur selten aktualisiert werden, knnen Sie den refresh()Befehl weglassen. So ist es z. B. bei einem Content-Mangement-System nicht notwendig, whrend
einer Session, mehrmals neue Daten von der Datenbank zu holen. Dies wrde die Datenbank ber
Gebhr belasten. Sie knnen also die Datenbank entlasten, indem Sie viel mit Objekten arbeiten,
die sich im Arbeitsspeicher der Datenbank db4o benden.
Wohingegen bei einer Online-Banking-Datenbankanwendung immer alle Daten mit der Methode
refresh() aktualisiert werden sollen. Dies stellt aber in diesem Fall keinen Nachteil dar, da bei
Online-Banking-Vorgngen die Benutzer bereit sind lnger zu warten, schon aus Grnden der
Sicherheit.

12.2 Update-Tiefe im Embedded Modus


Im Embedded-Modus knnen Sie die Methode cascadeOnUpdate() nicht verwenden, sondern nur
die Methode updateDepth() des Interfaces ExtObjectContainer (vgl. Kapitel Update-Tiefe). In
unten stehender Klasse UpdateWebSite.java habe ich die entsprechende Befehlszeile integriert.
Auerdem habe ich bestimmte Bereiche gelockt und einen Rollback mit zugehrigem Refresh und
Commit eingebaut (vgl. Kapitel Transaktionen). Etwas Neues ist auch dabei: Wir ersetzen eine
ArrayList durch eine andere ArrayList, wobei Sie allerdings darauf achten mssen, nicht mehr
bentigte Objekte separat zu lschen. Diese Vorgehensweise gibt es sowohl im Embedded-Modus
als auch im Solo-Modus, sie ist aber im Embedded-Modus vorzuziehen, da es hier, wenn Sie
gleichzeitig aus der ArrayList Elemente hinzufgen und entfernen, zu Problemen kommen kann.

package Kap12;

227

12 Embedded-Modus in einem Web-Projekt

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

import
import
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
Kap10.LockManager;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;
javax.servlet.http.HttpServletRequest;

public class UpdateWebSite {

228

public void updateWebSite(Link link, Link linkNeu,


ArrayList<Formatierung> formatierungNeu, ArrayList<Text> textAlt,
ArrayList<Bild> bildNeu, ArrayList<Bild> bildAlt,
ArrayList<PDF> pdfNeu, ArrayList<PDF> pdfAlt,
String reihenfolgeNeu, String ebeneNeu, HttpServletRequest request){
ObjectContainer db = null;
Formatierung form = new Formatierung();
Formatierung forme = new Formatierung();
WebSite w = new WebSite();
ArrayList<Text> textNeu = new ArrayList<Text>();
try {
db = (ObjectContainer)request.getSession().getAttribute("db4oClient");
/*Die Methode updateDepth(1) ermglicht es, einer ArrayList Objekte
hinzuzufgen, die sich innerhalb eines Objektes befinden.*/
db.ext().configure().updateDepth(1);
/*Die Klasse LockManager.java stellt Ihnen Methoden zur Verfgung,
die es Ihnen erlauben, bestimmte Dateien zu locken.*/
LockManager lockManager = new LockManager(db);
w = new WebSite(link, null, null, null, null, null);
ObjectSet<WebSite> resultWebSite = db.get(w);
w = resultWebSite.next();
if(lockManager.lock(w)){
/*Die alten Bildobjekte mssen gelscht werden.*/
for(Bild b: bildAlt){
ObjectSet<Bild> resultBild = db.get(b);

12.2 Update-Tiefe im Embedded Modus

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

while(resultBild.hasNext()){
Bild be = resultBild.next();
db.delete(be);
}
}
/*Die alten PDF-Objekte werden gelscht.*/
for(PDF pdf: pdfAlt){
ObjectSet<PDF> resultPdf = db.get(pdf);
while(resultPdf.hasNext()){
PDF p = resultPdf.next();
db.delete(p);
}
}
/*Der Name des Linkobjektes wird ersetzt.*/
ObjectSet<Link> resultLink = db.get(link);
link = resultLink.next();
String name = linkNeu.getName();
link.setName(name);
/*Alte Texte werden aus den entsprechenden Formatierungsobjekten
entfernt und anschlieend gelscht.*/
for(Text te: textAlt){
ObjectSet<Text> resultText = db.get(te);
while (resultText.hasNext()){
Text t = resultText.next();
ArrayList<Text> listText = new ArrayList<Text>();
listText.add(t);
Formatierung fo = new Formatierung(null, listText);
ObjectSet<Formatierung> resultFormat = db.get(fo);
while (resultFormat.hasNext()){
forme = resultFormat.next();
if(lockManager.lock(forme)){
ArrayList<Text> formatText = forme.getText();
formatText.remove(t);
db.delete(t);
forme.setText(formatText);
db.set(forme);
lockManager.unlock(forme);
}
}
}
}
/*Die neuen Texte werden den entsprechenden Formatierungsobjekten

229

12 Embedded-Modus in einem Web-Projekt

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

230

hinzugefgt.*/
for(Formatierung f : formatierungNeu){
Formatierung fo = new Formatierung(f.getName());
ArrayList<Text> al = f.getText();
ObjectSet<Formatierung> result = db.get(fo);
form = result.next();

if(lockManager.lock(form)){
for(Text t: al){
ArrayList<Text> texte = form.getText();
texte.add(t);
form.setText(texte);
db.set(form);
}
lockManager.unlock(form);
}

/*Die neuen Texte werden einer ArrayList<Text> textNeu hinzugefgt.*/


for(Formatierung f : formatierungNeu){
ArrayList<Text> al = f.getText();
Text te = null;
for(Text tex: al){
ObjectSet<Text> result = db.get(tex);
while (result.hasNext()){
te = result.next();
}

}
}

if(lockManager.lock(te)){
textNeu.add(te);
lockManager.unlock(te);
}

/*Der Link wird gespeichert und die entsprechen ArrayListen


des WebSite-Objektes werden ersetzt. Und anschlieend wird
das WebSite-Objekt gespeichert.*/
db.set(link);
w.setText(textNeu);
w.setBild(bildNeu);
w.setPdf(pdfNeu);
w.setReihenfolge(reihenfolgeNeu);
w.setEbene(ebeneNeu);
db.set(w);
lockManager.unlock(w);
}

12.2 Update-Tiefe im Embedded Modus

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

} catch (DatabaseFileLockedException e) {
/*Sollte es Probleme beim Speichern geben, werden
alle Abfragen im try-Block mit rollback() rckgngig gemacht
und die Daten im Arbeitspeicher werden mit refresh()
wieder auf den alten Stand gebracht.*/
db.rollback();

db.ext().refresh(forme, Integer.MAX_VALUE);
db.ext().refresh(form, Integer.MAX_VALUE);
db.ext().refresh(w, Integer.MAX_VALUE);
} finally{
db.commit();
}
}

Listing 12.11: UpdateWebSite.java


Wie verhlt es sich mit dem Lschvorgang? Gibt es eine Entsprechung zu der Methode cascadeOnDelete(), die es uns ermglicht das Linkobjekt und die Stringobjekte innerhalb der WebSite
mit dem Objekt der Klasse WebSite zu lschen? Nein. Wenn Sie ein Objekt der Klasse WebSite im
Embedded-Modus lschen wollen, mssen Sie die Objekte der Klasse Link und die Stringobjekte
separat lschen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

package Kap12;
import
import
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
Kap10.LockManager;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.ArrayList;
javax.servlet.http.HttpServletRequest;

public class DeleteWebSite {


public void deleteWebSite(Link link, HttpServletRequest request){
ObjectContainer db = null;
Formatierung form = new Formatierung();
WebSite w = new WebSite();
try {

231

12 Embedded-Modus in einem Web-Projekt

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

db = (ObjectContainer)request.getSession().getAttribute("db4oClient");
db.ext().configure().updateDepth(1);
w = new WebSite(link, null, null, null, null, null);
ObjectSet<WebSite> resultWebSite = db.get(w);
w = resultWebSite.next();
LockManager lockManager = new LockManager(db);
if(lockManager.lock(w)){
/*Die Objekte reihenfolge, ebene, Link, Bild
und PDF werden gelscht.*/
String reihenfolge = w.getReihenfolge();
db.delete(reihenfolge);
String ebene = w.getEbene();
db.delete(ebene);
Link l = w.getLink();
db.delete(l);
ArrayList<Bild> bild = w.getBild();
for(Bild b: bild){
db.delete(b);
}
db.delete(bild);
ArrayList<PDF> pdf = w.getPdf();
for(PDF p: pdf){
db.delete(p);
}
db.delete(pdf);
ArrayList<Text> text = w.getText();
/*Die Textobjekte werden aus den ArrayListen der entsprechenden
Formatierungsobjekte entfernt und dann gelscht.*/
for(Text te: text){
ObjectSet<Text> resultText = db.get(te);
while (resultText.hasNext()){
Text t = resultText.next();
ArrayList<Text> listText = new ArrayList<Text>();
listText.add(t);
Formatierung fo = new Formatierung(null, listText);
ObjectSet<Formatierung> resultFormat = db.get(fo);

232

12.2 Update-Tiefe im Embedded Modus

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

while (resultFormat.hasNext()){
form = resultFormat.next();
if(lockManager.lock(form)){
ArrayList<Text> formatText = form.getText();
formatText.remove(t);
form.setText(formatText);
db.set(form);
lockManager.unlock(form);
}
}
}
}
for(Text t: text){
db.delete(t);
}
db.delete(text);
/*Das Objekt w der Klasse WebSite wird gelscht.*/
db.delete(w);
lockManager.unlock(w);
}
} catch (DatabaseFileLockedException e) {
db.rollback();
db.ext().refresh(form, Integer.MAX_VALUE);
db.ext().refresh(w, Integer.MAX_VALUE);
} finally{
db.commit();
}
}
}
Listing 12.12: DeleteWebSite.java

233

13 Unser Content-Management-System

13.1 Allgemeines
In diesem Kapitel wollen wir anhand eines Content-Management-Systems alles bisher Gelernte
zu einem Ganzen verbinden. Sollte Ihnen in den folgenden Seiten noch etwas unklar sein, das
bereits in den vorangegangenen Seiten besprochen wurde, mchte ich Sie bitten zu den entsprechenden Kapiteln zurckzublttern. Dieses Kapitel mchte nur noch das gesamte Projekt und
die Zusammenhnge darstellen und nicht mehr auf Einzelheiten eingehen. Im Rahmen eines Buches ist es natrlich nur mglich ein Content-Mangement-System als Grundgerst darzustellen,
mit dem ich die wichtigsten Prinzipien darstellen mchte und das in keinem Fall den Anspruch
erhebt

alle Probleme, die in einer Applikation auftauchen knnen, zu lsen. Es soll Anregungen

liefern und es ist jedem freigestellt, es beliebig auszubauen.


Ich habe alle oben stehenden Abfragen bezglich Formatierungen in der Klasse FormatierungDaten.java im Ordner src/java/Datenbankabfragen abgelegt, der eigens fr alle Datenbankabfragen
erstellt wurde. All unsere Javaklassen, wie z.B. die Klasse Formatierung sind in einem Ordner
Datenbankentwurf zusammengefasst. Suchen Sie die Servlets des Projektes so nden Sie sie im
Ordner Servlets und die Filter im Ordner Eingang.

13.2 Eingabe, Auslesen, Lschen und ndern der Formatierungen


Lassen Sie uns jetzt Ein- und Ausgabemasken fr unsere CSS-Klassen erstellen. Es sind 5 verschiedene Dateien dafr notwendig, die wir teilweise bereits nher betrachtet haben oder dies
jetzt tun werden. Wir beginnen mit unseren Datenbankabfragen: Ich habe in unten stehender
Klasse FormatierungDaten.java Rollbacks, den Embedded-Modus und Semaphores miteingebaut.
Auerdem habe ich die Methode refresh() hinzugefgt, insbesondere bei den Methoden die Objekte der Klasse Formatierung auslesen, da es mir wichtig erscheint, die eingegeben, genderten
und gelschten Formatierungen sofort im Formular zu sehen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package Datenbankabfragen;
import
import
import
import
import
import
import
import
import
import
import
import
import

Datenbankentwurf.Formatierung;
Datenbankentwurf.Text;
Kap10.LockManager;
java.io.IOException;
java.util.Collection;
java.util.ArrayList;
com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectSet;
com.db4o.ext.DatabaseFileLockedException;
java.util.Iterator;
java.util.List;
javax.servlet.http.HttpServletRequest;

235

13 Unser Content-Management-System

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

public class FormatierungDaten {


/*Die Methode speichern() speichert Objekte der Klasse
Formatierung.*/
public void speichern(Formatierung f, HttpServletRequest request){
ObjectContainer db = null;
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
db.set(f);
} catch (DatabaseFileLockedException e) {
db.rollback();
db.ext().refresh(f, Integer.MAX_VALUE);
} finally{
db.commit();
}
}
/*Die Methode auslesen() liest alle Objekte der Klasse
Formatierung aus.*/
public ArrayList<Formatierung> auslesen(HttpServletRequest request){
ObjectContainer db = null;
ArrayList<Formatierung> f = new ArrayList<Formatierung>();
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
Formatierung p = new Formatierung(null, null);
ObjectSet<Formatierung> result = db.get(p);
while (result.hasNext()){
p = result.next();
db.ext().refresh(p, Integer.MAX_VALUE);
f.add(p);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return f;
}

236

13.2 Eingabe, Auslesen, Lschen und ndern der Formatierungen

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

/*Die Methode auslesenEinzeln() liest bestimmte


Objekte der Klasse Formatierung aus.*/
public Formatierung auslesenEinzeln
(String name, HttpServletRequest request){
ObjectContainer db = null;
Formatierung fo = new Formatierung();
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
Formatierung p = new Formatierung(name, null);
ObjectSet<Formatierung> result = db.get(p);
fo = result.next();
db.ext().refresh(fo, Integer.MAX_VALUE);
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return fo;
}
/*Die Methode loeschen() lscht ein bestimmtes Objekt der Klasse
Formatierung.*/
public void loeschen(Formatierung f, HttpServletRequest request){
ObjectContainer db = null;
Formatierung p = null;
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
ObjectSet<Formatierung> result = db.get(f);
p = result.next();
ArrayList<Text> al = p.getText();
LockManager lockManager = new LockManager(db);
for(Text te: al){
if(lockManager.lock(te)){

237

13 Unser Content-Management-System

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

238

db.delete(te);
}
}

lockManager.unlock(te);

db.delete(al);
if(lockManager.lock(p)){
db.delete(p);
lockManager.unlock(p);
}
} catch (DatabaseFileLockedException e) {
db.rollback();
db.ext().refresh(p, Integer.MAX_VALUE);
} finally{
db.commit();
}
}
/*Die Methode aendern() ndert Objekte der Klasse
Formatierung.*/
public void aendern(Formatierung f,
Formatierung fo, HttpServletRequest request){
ObjectContainer db = null;
Formatierung p = null;
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
ObjectSet<Formatierung> result = db.get(f);
p = result.next();
LockManager lockManager = new LockManager(db);
if(lockManager.lock(p)){
String name = fo.getName();
p.setName(name);
db.set(p);
lockManager.unlock(p);
}

13.2 Eingabe, Auslesen, Lschen und ndern der Formatierungen

163
164
165
166
167
168
169
170
171

} catch (DatabaseFileLockedException e) {
db.rollback();
db.ext().refresh(p, Integer.MAX_VALUE);
} finally{
db.commit();
}
}

Listing 13.1: FormatierungDaten.java

Die Datenbankabfragen stellen die Grundlage fr unser erstes Modul dar, das es uns ermglichen
soll, CSS-Formatierungen zu speichern, zu lschen und zu ndern. Unten stehend sehen Sie unser
erstes Formular, in das Sie alle CSS-Formatierungen eingeben knnen.

Abbildung 13.1: Eingabemaske fr unsere Formatierungen

Wollen Sie die Formatierungen ndern oder lschen, knnen Sie das in folgendem Formular. Es
besteht aus einer Auswahlliste, das es Ihnen ermglicht das entsprechende Format auszuwhlen:

239

13 Unser Content-Management-System

Abbildung 13.2: Lschen und ndern der Formatierungen


Um diese beiden Formulare mit Servlets und JSPs realisieren zu knnen, brauchen wir auerdem
die bereits weiter oben erstellten Klassen Formatierung und FormatierungFilter, die sich in den
Ordnern src/java/Datenbankentwurf und src/java/Eingang benden.
Wir fahren mit dem Servlet eingabeFormatierungServlet.java fort. In diesem werden die Formatierungsdaten direkt aus der Datenbank ein- und ausgelesen und an das JSP eingabeFormatierung.jsp weitergesendet, das Sie im Anschlu an das Servlet nden knnen.
Zuerst mssen wir aber unser Servlet in die web.xml eintragen und der dazugehrige Eintrag
sieht wie folgt aus:

1
2
3
4
5
6
7
8
9
10

<servlet>
<servlet-name>eingabeFormatierung</servlet-name>
<servlet-class>Servlets.eingabeFormatierungServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>eingabeFormatierung</servlet-name>
<url-pattern>/eingabeFormatierung</url-pattern>
</servlet-mapping>

Listing 13.2: webFormatierung.xml


Wir wollen bei unserem Servlet auf zwei Aspekte unser besonderes Augenmerk richten: Erstens
auf das ndern unserer Formatierungsdaten. Weiter oben haben wir bereits erwhnt, dass Daten

240

13.2 Eingabe, Auslesen, Lschen und ndern der Formatierungen

in der Datenbank db4o mit den Methoden get() und set() gendert werden. Zuerst wird die Datenbank genet, das Objekt mit get() ausgelesen, dann gendert, anschlieend mit set() wieder
eingelesen und zum Schlu wird die Datenbank wieder geschlossen. Sie erstellen im Servlet ein
Formatierungsobjekt mit neuem und eines mit altem Namen und bergeben beide der Methode
aendern() der Klasse FormatierungDaten. In der Methode aendern() werden die Methoden get()
und set() immer mit dem gleichen Objekt ausgefhrt. So wird das ursprngliche Objekt gendert
und kein neues erstellt.
Und zweitens auf das Zusammenspiel Filter Servlet. Wie Sie in unten stehendem Listing sehen
knnen, sind die Programmierzeilen, die die Formatierungsobjekte aus der Datenbank auslesen,
im Servlet nicht notwendig, da diese Zeilen in den Filter ausgelagert wurden. Jedes Mal, wenn
Formatierung der Datenbank hinzugefgt oder gelscht worden sind, werden die Daten automatisch aktualisiert. Diese Funktion des Filters erspart Ihnen jede Menge Arbeit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

package Servlets;
import
import
import
import
import
import
import
import
import
import
import
import

Datenbankabfragen.FormatierungDaten;
Datenbankentwurf.Formatierung;
java.io.IOException;
java.util.ArrayList;
java.util.Collection;
java.util.HashMap;
java.util.Map;
javax.servlet.http.HttpSession;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.ServletException;

public class eingabeFormatierungServlet extends HttpServlet {


protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
/*Sollte error nicht leer sein, bitte entsprechendes
Session-Attribut lschen*/
request.getSession().removeAttribute("errors");
/*Wir instanziieren eine HashMap, die Fehlermeldungen speichern
soll*/
Map errors = new HashMap();
/*Wir deklarieren eine Variablen name*/
String name = null;
/*Wurde im Formular auf den Submit-Button Eingabe geklickt, wird
untenstehender Ausdruck wahr*/

241

13 Unser Content-Management-System

if(request.getParameter("Eingabe")!= null ){

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

/*Ist in dem Formularfeld name der Name der Formatierung


eingegeben, ist folgende Bedingung der if-Struktur wahr*/
if (request.getParameter("name")!= null
&& request.getParameter("name").length()>0){
/*Es wird der Parameter name des Formulars der Variablen
name bergeben*/
name = request.getParameter("name");
} else{
/*Wurde in das Formularfeld name nichts eingegeben, wird
der HashMap errors ein Element hinzugefgt*/
errors.put("name", "Name fehlt!");
}
/*Besitzt die HashMap errors Elemente*/
if(errors.size()> 0){
/*wird der Session die HashMap errors als Attribut bergeben*/
request.getSession().setAttribute("errors", errors);
/*Der Request und seine Daten werden zu dieser
Seite weitergeleitet.*/
request.getRequestDispatcher("eingabeFormatierung.jsp").
forward(request, response);
/*Sind Daten in das Formularfeld eingegeben worden, wird
der else-Zweig abgearbeitet*/
}else{
//Das Formatierungsobjekt wird in der Datenbank gespeichert
Formatierung f = new Formatierung(name);
FormatierungDaten fd = new FormatierungDaten();
fd.speichern(f, request);

//Zu dieser Seite mssen die Daten zurckgeschickt werden.


request.getRequestDispatcher("eingabeFormatierung.jsp").
forward(request, response);

/*Wurde im JSP auf den Hyperlink Eingabe (e) geklickt, wird


der folgende else if-Zweig ausgefhrt*/
}else if(request.getParameter("e")!= null){
//Zu dieser Seite mssen die Daten zurckgeschickt werden.
request.getRequestDispatcher("eingabeFormatierung.jsp").

242

13.2 Eingabe, Auslesen, Lschen und ndern der Formatierungen

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

forward(request, response);
/*Wurde im JSP auf den Hyperlink ndern oder Lschen geklickt, wird
der folgende else if-Zweig ausgefhrt*/
}else if(request.getParameter("l")!= null ||
request.getParameter("a")!= null){
/*Da die Daten mit RequestDispatcher weitergeleitet werden,
wird der Filter abgearbeitet, der die Formatierungsobjekte
aus der Datenbank ausliest, und es kann auf folgende
Programmierzeilen verzichtet werden, die aktuellen Daten
aus der Datenbank auslesen:
request.getSession().removeAttribute("formatierung");
FormatierungDaten format = new FormatierungDaten();
ArrayList<Formatierung> formatierung = format.auslesen();
request.getSession().setAttribute("formatierung", formatierung);*/
//Zu dieser Seite mssen die Daten zurckgeschickt werden.
request.getRequestDispatcher("eingabeFormatierung.jsp").
forward(request, response);
/*Wurde im Formular auf den Submit-Button Loeschen geklickt
wird der folgende else if-Zweig ausgefhrt*/
}else if(request.getParameter("Loeschen")!= null){
FormatierungDaten format = new FormatierungDaten();
/*Es wird ein neues Formatierungsobjekt instanziiert*/
Formatierung f = new Formatierung();
/*Der Name des zu lschenden Formatierungsobjekt
wird aus der Auswahlliste ausgelesen*/
name = request.getParameter("formatierungSelect");
/*Bei diesem Formatierungsobjekt, das gelscht werden soll,
wird der Name der Formatierung festgelegt */
f.setName(name);
/*Das zu lschende Formatierungsobjekt wird der Methode
loeschen als Parameter bergeben*/
format.loeschen(f, request);
/*Die Seite wird wieder zu der Lschen-Seite mit GET
zurckgeschickt*/
request.getRequestDispatcher("eingabeFormatierung.jsp?l=ja").
forward(request, response);

243

13 Unser Content-Management-System

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

244

/*Wenn im Formular auf den Button AendernAuswahl geklickt wurde,


wird folgendes abgearbeitet*/
}else if(request.getParameter("AendernAuswahl") != null){
/*Gibt es bereits ein Session-Attribut altName, sollte
dies erst gelscht werden, da es unten durch ein
Neues ersetzt wird*/
request.getSession().removeAttribute("altName");
/*Der Name aus der Auswahlliste wird der Variable altName
und anschlieend der Session bergeben*/
String altName = request.getParameter("formatierungSelect");
request.getSession().setAttribute("altName", altName);
/*Die Daten werden zurckgesendet*/
request.getRequestDispatcher("eingabeFormatierung.jsp").
forward(request, response);
/*Folgendes wird ausgefhrt, wenn im Formular auf den Button
Aendern geklickt wurde*/
}else if (request.getParameter("Aendern") != null){
FormatierungDaten format = new FormatierungDaten();
/*Der alte Name des Formatierungsobjektes wird der
Variablen altName bergeben*/
String altName = (String)request.getSession().getAttribute("altName");
/*Der neue Name wird der Variablen neuName bergeben*/
String neuName = request.getParameter("name");
/*Instanziierung eines Formatierungsobjektes mit
dem alten Namen*/
Formatierung f = new Formatierung(altName);
/*Instanziierung eines Formatierungsobjektes mit
dem neuen Namen*/
Formatierung fo = new Formatierung(neuName);
/*Die Formatierungsobjekte mit neuem und alten
Namen werden der Methode aendern bergeben*/
format.aendern(f, fo, request);

/*Der Request wird mit GET wieder zu der ndern-Anfangsseite


zurckgeschickt*/
request.getRequestDispatcher("eingabeFormatierung.jsp?a=ja").
forward(request, response);

13.2 Eingabe, Auslesen, Lschen und ndern der Formatierungen

184
185
186
187
188
189
190

protected void doPost(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

Listing 13.3: Programmierlogik der Formatierungsformulare


Die Daten werden zwischen dem Servlet und dem JSP eingabeFormatierung.jsp hin- und hergesendet, wobei die Daten im JSP nur ein- und ausgegeben werden und im Servlet direkt aus der
Datenbank kommen. Beim Lschen der Formatierungsobjekte knnten Sie noch zustzlich eine
if-Abfrage einbauen, die verhindert, dass Formate gelscht werden, die noch Objekte der Klasse
Text beinhalten (vgl. Kapitel Ergnzende Bemerkungen zum Lschvorgang von Objekten der
Klasse Formatierung  ).
Unser unten stehendes JSP besteht zum Groteil aus CSS, HTML und Elementen der Standard
Tag Library (JSTL) und bendet sich in unserem Projekt direkt im Ordner web.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<!--Die CSS-Datei befindet sich im Ordner web/Styles-->
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>Eingabe, Aendern und Loeschen von Formatierungen</title>
</head>
<body>
<!--Das Bild oben.jpg befindet sich im Ordner web/Bilder-->
<div class="box1"><img src="Bilder/oben.jpg" width="800" height="100"></div>
<div class= "box2">
<span class="menu">
<!--wird auf den Hyperlink Eingabe, Aendern oder Loeschen geklickt,
wird das JSP mit GET zum Servlet eingabeFormatierung weitergeleitet-->
<a href="<%=request.getContextPath()%>/eingabeFormatierung?e=ja">
Eingabe
</a>
<a href="<%=request.getContextPath()%>/eingabeFormatierung?a=ja">
&Auml;ndern
</a>

245

13 Unser Content-Management-System

<a href="<%=request.getContextPath()%>/eingabeFormatierung?l=ja">
L&ouml;schen
</a>
</span>
</div>
<div class= "box3">
<span class="font4">

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

<!--Hier werden die Daten aus der HashMap, die die Fehlermeldungen
speichert, ausgelesen. Sollte nichts in das Formularfeld name
eingetragen worden sein, wird eine Fehlermeldung ausgegeben.-->
<c:if test="${errors.name != null}">
<c:out value="${errors.name}"/>
</c:if>
<!--Die Daten des Formulars werden an das Servlet
mit Namen eingabeFormatierung weitergeleitet-->
<form name=""
action="<%=request.getContextPath()%>/eingabeFormatierung"
method="GET">
<!--Das Formular befindet sich in einer Tabelle -->
<table align="center" valign="middle">
<!--Wurde entweder auf den Hyperlink Aendern (a) oder
Loeschen (l) geklickt, wird folgende Bedingung der
if-Struktur wahr-->
<c:if test="${param.a != null || param.l != null}">
<tr>
<td>
Formatierung
</td>
<td>
<!--Hier werden die Daten aus der ArrayList, die im Filter
der Session uebergeben werden, in einer
Auswahlliste des Formulars ausgelesen. -->
<select name="formatierungSelect" >
<c:forEach var="formatierung" items="${formatierung}">
<!--Mit formatierung.name kann direkt auf den Namen
der Formatierung zugegriffen werden-->
<option value="<c:out value='${formatierung.name}' />">
<c:out value="${formatierung.name}" />
</option>
</c:forEach>
</select>
</td>
</tr>

246

13.2 Eingabe, Auslesen, Lschen und ndern der Formatierungen

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

</c:if>
<!--Wurde auf den Hyperlink Eingabe (e) geklickt, wird
folgende if-Struktur ausgefuehrt-->
<c:if test="${param.e != null}">
<tr>
<td>CSS-Format</td>
<td><input type="text" name="name" value=""></td>
</tr>
<tr>
<td colspan="2" align="center">
<!--Das Formular hat einen Submit-Button mit Namen Eingabe -->
<input type="submit" name="Eingabe"
value="Eingabe" class="button" />
</td>
</tr>
</c:if>
<!--Wurde auf den Hyperlink Aendern (a) geklickt, wird
folgende Bedingung wahr-->
<c:if test="${param.a != null}">
<tr>
<td colspan="2" align="center">
<!--Das Formular hat einen Submit-Button mit
Namen AendernAuswahl -->
<input type="submit" name="AendernAuswahl"
value="&Auml;ndern" class="button" />
</td>
</tr>
</c:if>
<!--Wurde auf den Hyperlink Loeschen (l) geklickt, wird
folgende Bedingung wahr-->
<c:if test="${param.l != null}">
<tr>
<td colspan="2" align="center">
<!--Das Formular hat einen Submit-Button mit
Namen Loeschen -->
<input type="submit" name="Loeschen"
value="L&ouml;schen" class="button" />
</td>
</tr>
</c:if>
<!--Wurde auf den Submit-Button AendernAuswahl geklickt, wird

247

13 Unser Content-Management-System

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

folgende Bedingung der if-Struktur wahr-->


<c:if test="${param.AendernAuswahl != null
&& param.formatierungSelect != null}">
<tr>
<td>CSS-Format</td>
<!--Die Variable altName enthaelt den Namen der
Formatierung, der veraendert werden soll-->
<td><input type="text" name="name"
value="<c:out value='${altName}' />"></td>
</tr>
<tr>
<td colspan="2" align="center">
<!--Das Formular hat einen Submit-Button mit Namen Aendern -->
<input type="submit" name="Aendern"
value="&Auml;ndern" class="button" />
</td>
</tr>
</c:if>
</table>
</form>
</span>
</div>
</body>
</html>

Listing 13.4: Formular Eingabe, Lschen und ndern von Formatierungsobjekten (eingabeFormatierung.jsp)

13.3 Eingabe von Objekten der Klasse WebSite


Kommen wir zu dem Herzstck unseres Content-Management-Systems: Wir geben die Daten fr
unsere Webseiten ein und wieder aus. Alle wichtigen diesbezgliche Abfragen benden sich in
der Klasse WebSiteDaten im Ordner src/java/Datenbankabfragen. Ich habe die Abfragen um
Rollbacks, Client-Server-Modus und um Semaphores ergnzt.

1
2
3
4
5
6
7
8
9

package Datenbankabfragen;
import
import
import
import
import
import
import

248

Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
Kap10.LockManager;

13.3 Eingabe von Objekten der Klasse WebSite

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

import
import
import
import
import
import
import
import
import
import
import
import
import
import

com.db4o.Db4o;
com.db4o.ObjectContainer;
com.db4o.ObjectServer;
com.db4o.ObjectSet;
com.db4o.config.ObjectClass;
com.db4o.ext.DatabaseFileLockedException;
com.db4o.query.Predicate;
com.db4o.query.Query;
java.io.IOException;
java.util.ArrayList;
java.util.Collections;
java.util.Comparator;
javax.servlet.ServletContext;
javax.servlet.http.HttpServletRequest;

public class WebSiteDaten {


/*Die Methode addWebSite() fgt der Datenbank ein Objekt der Klasse
WebSite hinzu.*/
public void addWebSite(Link link, ArrayList<Formatierung> formatierung,
ArrayList<Bild> bild, ArrayList<PDF> pdf,
String reihenfolge, String ebene, HttpServletRequest request){
ObjectContainer db = null;
WebSite w = new WebSite();
Formatierung form = new Formatierung();
ArrayList<Text> text = new ArrayList<Text>();
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
db.ext().configure().updateDepth(1);
LockManager lockManager = new LockManager(db);
for(Formatierung f : formatierung){
Formatierung fo = new Formatierung(f.getName());
ObjectSet<Formatierung> result = db.get(fo);
form = result.next();
if(lockManager.lock(form)){
ArrayList<Text> al = f.getText();
for(Text t: al){
ArrayList<Text> textNeu = form.getText();
textNeu.add(t);
form.setText(textNeu);
db.set(form);

249

13 Unser Content-Management-System

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

250

}
}
}

lockManager.unlock(form);

for(Formatierung f : formatierung){
ArrayList<Text> al = f.getText();
for(Text t : al){
ObjectSet<Text> result = db.get(t);
Text te = result.next();
if(lockManager.lock(te)){
text.add(te);
lockManager.unlock(te);
}
}
}
w.setLink(link);
w.setText(text);
w.setBild(bild);
w.setPdf(pdf);
w.setReihenfolge(reihenfolge);
w.setEbene(ebene);
db.set(w);
} catch (DatabaseFileLockedException e) {
db.rollback();
db.ext().refresh(form, Integer.MAX_VALUE);
db.ext().refresh(w, Integer.MAX_VALUE);
} finally{
db.commit();
}
}
/*Die Methode updateWebSite() ndert die Daten eines Objektes
der Klasse WebSite.*/
public void updateWebSite(Link link, Link linkNeu,
ArrayList<Formatierung> formatierungNeu, ArrayList<Text> textAlt,
ArrayList<Bild> bildNeu, ArrayList<Bild> bildAlt,
ArrayList<PDF> pdfNeu, ArrayList<PDF> pdfAlt,
String reihenfolgeNeu, String ebeneNeu, HttpServletRequest request){
ObjectContainer db = null;
Formatierung form = new Formatierung();
Formatierung forme = new Formatierung();
WebSite w = new WebSite();

13.3 Eingabe von Objekten der Klasse WebSite

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

ArrayList<Text> textNeu = new ArrayList<Text>();


try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
db.ext().configure().updateDepth(1);
LockManager lockManager = new LockManager(db);
w = new WebSite(link, null, null, null, null, null);
ObjectSet<WebSite> resultWebSite = db.get(w);
w = resultWebSite.next();
if(lockManager.lock(w)){
for(Bild b: bildAlt){
ObjectSet<Bild> resultBild = db.get(b);
while(resultBild.hasNext()){
Bild be = resultBild.next();
db.delete(be);
}
}
for(PDF pdf: pdfAlt){
ObjectSet<PDF> resultPdf = db.get(pdf);
while(resultPdf.hasNext()){
PDF p = resultPdf.next();
db.delete(p);
}
}
ObjectSet<Link> resultLink = db.get(link);
link = resultLink.next();
String name = linkNeu.getName();
link.setName(name);
for(Text te: textAlt){
ObjectSet<Text> resultText = db.get(te);
while (resultText.hasNext()){
Text t = resultText.next();
ArrayList<Text> listText = new ArrayList<Text>();
listText.add(t);
Formatierung fo = new Formatierung(null, listText);
ObjectSet<Formatierung> resultFormat = db.get(fo);
while (resultFormat.hasNext()){
forme = resultFormat.next();

251

13 Unser Content-Management-System

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

252

if(lockManager.lock(forme)){
ArrayList<Text> formatText = forme.getText();
formatText.remove(t);
db.delete(t);
forme.setText(formatText);
db.set(forme);
lockManager.unlock(forme);

}
}
}

for(Formatierung f : formatierungNeu){
Formatierung fo = new Formatierung(f.getName());
ArrayList<Text> al = f.getText();
ObjectSet<Formatierung> result = db.get(fo);
form = result.next();

if(lockManager.lock(form)){
for(Text t: al){
ArrayList<Text> texte = form.getText();
texte.add(t);
form.setText(texte);
db.set(form);
}
lockManager.unlock(form);
}

for(Formatierung f : formatierungNeu){
ArrayList<Text> al = f.getText();
Text te = null;
for(Text tex: al){
ObjectSet<Text> result = db.get(tex);
while (result.hasNext()){
te = result.next();
}

}
}

if(lockManager.lock(te)){
textNeu.add(te);
lockManager.unlock(te);
}

db.set(link);
w.setText(textNeu);

13.3 Eingabe von Objekten der Klasse WebSite

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254

w.setBild(bildNeu);
w.setPdf(pdfNeu);
w.setReihenfolge(reihenfolgeNeu);
w.setEbene(ebeneNeu);
db.set(w);
lockManager.unlock(w);
}
} catch (DatabaseFileLockedException e) {
db.rollback();
db.ext().refresh(forme, Integer.MAX_VALUE);
db.ext().refresh(form, Integer.MAX_VALUE);
db.ext().refresh(w, Integer.MAX_VALUE);
} finally{
db.commit();
}
}
/*Die Methode deleteWebSite() lscht ein bestimmtes Objekt der
Klasse WebSite und alle darin enthaltenen Objekte.*/
public void deleteWebSite(Link link, HttpServletRequest request){
ObjectContainer db = null;
Formatierung form = new Formatierung();
WebSite w = new WebSite();
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
db.ext().configure().updateDepth(1);
w = new WebSite(link, null, null, null, null, null);
ObjectSet<WebSite> resultWebSite = db.get(w);
w = resultWebSite.next();
LockManager lockManager = new LockManager(db);
if(lockManager.lock(w)){
String reihenfolge = w.getReihenfolge();
db.delete(reihenfolge);
String ebene = w.getEbene();
db.delete(ebene);

253

13 Unser Content-Management-System

255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303

254

Link l = w.getLink();
db.delete(l);
ArrayList<Bild> bild = w.getBild();
for(Bild b: bild){
db.delete(b);
}
db.delete(bild);
ArrayList<PDF> pdf = w.getPdf();
for(PDF p: pdf){
db.delete(p);
}
db.delete(pdf);
ArrayList<Text> text = w.getText();
for(Text te: text){
ObjectSet<Text> resultText = db.get(te);
while (resultText.hasNext()){
Text t = resultText.next();
ArrayList<Text> listText = new ArrayList<Text>();
listText.add(t);
Formatierung fo = new Formatierung(null, listText);
ObjectSet<Formatierung> resultFormat = db.get(fo);
while (resultFormat.hasNext()){
form = resultFormat.next();
if(lockManager.lock(form)){
ArrayList<Text> formatText = form.getText();
formatText.remove(t);
form.setText(formatText);
db.set(form);

}
}

lockManager.unlock(form);
}
}

for(Text t: text){
db.delete(t);
}

13.3 Eingabe von Objekten der Klasse WebSite

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

db.delete(text);
db.delete(w);
lockManager.unlock(w);
}
} catch (DatabaseFileLockedException e) {
db.rollback();
db.ext().refresh(form, Integer.MAX_VALUE);
db.ext().refresh(w, Integer.MAX_VALUE);
} finally{
db.commit();
}
}
/*Die Methode auslesen() liest alle Objekte der Klasse WebSite aus*/
public ArrayList<WebSite> auslesen(HttpServletRequest request){
ObjectContainer db = null;
ArrayList<WebSite> f = new ArrayList<WebSite>();
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
WebSite w = new WebSite(null, null, null, null, null, null);
ObjectSet<WebSite> result = db.get(w);
while (result.hasNext()){
w = result.next();
f.add(w);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return f;
}
/*Die Methode auslesenLinkErste() liest alle Objekte der
Klasse Link aus, die in der oberen Menleiste
auftauchen sollen.*/
public ArrayList<Link> auslesenLinkErste(HttpServletRequest request){
ObjectContainer db = null;
ArrayList<Link> al = new ArrayList<Link>();

255

13 Unser Content-Management-System

353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401

256

try{
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
Comparator<WebSite> comp = new Comparator<WebSite>(){
public int compare(WebSite w, WebSite we){
return w.getLink().getName().compareTo(we.getLink().getName());
}
};
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
return webSite.getEbene().equals("");
}
}, comp);
while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
Collections.reverse(al);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return al;
}
/*Die Methode auslesenLink() liest alle Objekte der Klasse Link
alphabetisch sortiert aus.*/
public ArrayList<Link> auslesenLink(HttpServletRequest request){
ObjectContainer db = null;
ArrayList<Link> al = new ArrayList<Link>();
try{
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
Comparator<WebSite> comp = new Comparator<WebSite>(){
public int compare(WebSite w, WebSite we){
return w.getLink().getName().compareTo(we.getLink().getName());
}
};
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {

13.3 Eingabe von Objekten der Klasse WebSite

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450

public boolean match(WebSite webSite){


return true;
}
}, comp);
while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return al;
}
/*Die Methode auslesenLinkZweite() liest alle Links der
Klasse Link aus, die auf der linken Menleiste auftauchen
sollen.*/
public ArrayList<Link> auslesenLinkZweite
(String reihenfolge, HttpServletRequest request){
ObjectContainer db = null;
ArrayList<Link> al = new ArrayList<Link>();
try{
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
Query query = db.query();
query.constrain(WebSite.class);
query.descend("reihenfolge").constrain(reihenfolge);
query.descend("ebene").constrain("").not();
query.descend("ebene").orderAscending();
ObjectSet<WebSite> result = query.execute();
while (result.hasNext()){
WebSite w = result.next();
Link l = w.getLink();
al.add(l);
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}

257

13 Unser Content-Management-System

451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499

258

return al;
}
/*Die Methode auslesenLinkReihenfolge() liest den
Inhalt des Strings Reihenfolge fr ein bestimmtes
Objekt der Klasse Link aus, wobei das dazugehrige
Objekt der Klasse WebSite die Bedingung erfllen muss,
dass der darin enthaltene String ebene leer ist.*/
public String auslesenLinkReihenfolge
(final String linkName, HttpServletRequest request){
ObjectContainer db = null;
String reihenfolge = new String();
try{
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
return webSite.getLink().getName().equals(linkName)
&& webSite.getEbene().equals("");
}
});
WebSite w = result.next();
reihenfolge = w.getReihenfolge();
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return reihenfolge;
}
/*Die Methode auslesenLinkReihenfolge() liest den
Inhalt des Strings Reihenfolge fr ein bestimmtes
Objekt der Klasse Link aus.*/
public String auslesenReihenfolge
(final String linkName, HttpServletRequest request){
ObjectContainer db = null;
String reihenfolge = new String();
try{
db = (ObjectContainer)request.getSession().

13.3 Eingabe von Objekten der Klasse WebSite

500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548

getAttribute("db4oClient");
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
return webSite.getLink().getName().equals(linkName);
}
});
WebSite w = result.next();
reihenfolge = w.getReihenfolge();
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return reihenfolge;
}
/*Die Methode auslesenText() liest die Objekte der Klasse Text
und die dazugehrigen Objekte der Klasse Formatierung aus,
die zu einer bestimmten WebSite gehren.*/
public ArrayList<Formatierung> auslesenText
(final String linkName, HttpServletRequest request){
ObjectContainer db = null;
ArrayList<Formatierung> af = new ArrayList<Formatierung>();
Formatierung f = new Formatierung(null, null);
ArrayList<Text> text = new ArrayList<Text>();
try{
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
ObjectSet<WebSite> result = db.query(new Predicate<WebSite>() {
public boolean match(WebSite webSite){
return webSite.getLink().getName().equals(linkName);
}
});
while (result.hasNext()){
WebSite w = result.next();
text = w.getText();
}
ObjectSet<Formatierung> resultFormat = db.get(f);
while (resultFormat.hasNext()){
Formatierung form = resultFormat.next();

259

13 Unser Content-Management-System

549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

ArrayList<Text> at = form.getText();
for(Text t :at){
for(Text te : text){
if(t.getName().equals(te.getName())){
ArrayList<Text> al = new ArrayList<Text>();
al.add(t);
Formatierung fo = new Formatierung(form.getName(),al);
af.add(fo);
}
}
}
}
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return af;
}
/*Die Methode auslesenEinzeln() liest bestimmte Objekte
der Klasse WebSite aus.*/
public WebSite auslesenEinzeln
(String linkName, HttpServletRequest request){
ObjectContainer db = null;
WebSite we = new WebSite();
Link l = new Link(linkName);
try {
db = (ObjectContainer)request.getSession().
getAttribute("db4oClient");
WebSite w = new WebSite(l, null, null, null, null, null);
ObjectSet<WebSite> result = db.get(w);
we = result.next();
} catch (DatabaseFileLockedException e) {
e.printStackTrace();
}
return we;
}
}
Listing 13.5: WebSiteDaten.java

260

13.3 Eingabe von Objekten der Klasse WebSite

13.3.1 Eingabe des Hyperlinks, der Reihenfolge und der Ebene


Unser Eingabeformular fr die Objekte der Klasse WebSite besteht aus vier JSP-Seiten, jeweils
eine fr die Eingabe von Hyperlinks, von Texten, von Bildern und von PDFs.
Zuerst geben wir den Namen des Hyperlinks, die Reihenfolge und die Ebene mit unten stehendem
Formular ein:

Abbildung 13.3: Eingabe von Hyperlinks

Wie sieht das Listing dazu aus? Das Listing wird auf zwei JSP-Seiten aufgeteilt. Die Menleiste
bendet sich in einer separaten Datei, die mit einem Include in eingabeWebSiteLink.jsp eingefgt
wird. Hier das JSP menueEingabeWebsite.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page language="java" %>
<!--Klicken Sie auf einen der unten stehenden Links, wird das JSP
mit GET an das entsprechende Servlet weitergesendet.-->
<a href="<%=request.getContextPath()%>/eingabeWebSite?eWeb=ja">
Eingabe Web
</a>
<a href="<%=request.getContextPath()%>/aendernWebSite?aWeb=ja">
&Auml;ndern Web
</a>
<a href="<%=request.getContextPath()%>/loeschenWebSite?lWeb=ja">
L&ouml;schen Web
</a>
Listing 13.6: menueEingabeWebSite.jsp

Hier das zweite JSP, in das oben stehendes menueEingabeWebSite.jsp mit der Direktive include
eingebettet wird:

<%@page language="java" %>

261

13 Unser Content-Management-System

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>Eingabe Link</title>
</head>

262

<body>
<div class="box1"><img src="Bilder/oben.jpg"
width="800" height="100">
</div>
<div class= "box2">
<span class="menu">
<!--Die Datei, die die Menueleiste zum Inhalt hat, wird
mithilfe von include eingebettet-->
<%@include file="menueEingabeWebSite.jsp" %>
</span>
</div>
<div class= "box3">
<span class="font4">
<!--Sollte in die Felder Link und Reihenfolge nichts eingegeben
worden sein, wird eine Fehlermeldung ausgegeben.-->
<c:if test="${errors != null}">
<c:forEach var="errors" items="${errors}">
<c:out value="${errors.value}" />
</c:forEach>
<br><br>
</c:if>
<!--Die Daten des Formulars werden mit GET an das Servlet
eingabeWebSiteServlet.java und anschliessend an
eingabeWebSiteText.jsp weitergesendet.-->
<form name=""
action="<%=request.getContextPath()%>/eingabeWebSite"
method="GET">
<!--Das Formular befindet sich in einer Tabelle-->
<table align="center" valign="middle">
<tr>
<td>Link</td>
<td>

13.3 Eingabe von Objekten der Klasse WebSite

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

<!--Die Felder param.Link, param.Reihenfolge und param.Ebene


haben Inhalt, wenn ein Pflichtfeld nicht ausgefuellt wurde.-->
<input type="text" name="Link"
value="<c:out value='${param.Link}'/>">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td>Reihenfolge</td>
<td>
<input type="text" name="Reihenfolge"
value="<c:out value='${param.Reihenfolge}'/>"
size="3">
<input type="text" name="Ebene"
value="<c:out value='${param.Ebene}'/>"
size="3">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<!--Klicken Sie auf den Button Weiter, gelangen Sie zum Formular
fuer die Eingabe von Texten.-->
<input type="submit" name="WeiterLink"
value="Weiter" class="button" />
</td>
</tr>
</table>
</form>
</span>
</div>
</body>
</html>
Listing 13.7: eingabeWebSiteLink.jsp

263

13 Unser Content-Management-System

13.3.2 Eingabe von Text


Das nchste Formular ermglicht es uns Text einzugeben. Wobei Sie auch die Mglichkeit haben
mehrere Textfelder zu erstellen, indem Sie auf den Button Text hinzufgen klicken:

Abbildung 13.4: Texteingabe


Sobald Sie in diesem Formular auf Text hinzufgen klicken, wird der Text einer ArrayList hinzugefgt, die dann sofort im Formular wieder ausgelesen wird. Klicken Sie auf den Button Weiter
gelangen Sie zu dem nchsten Eingabeformular fr Bilder.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>Eingabe Text</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>

264

<div class= "box2">


<span class="menu">
<!--Die Datei, die die Menueleiste zum Inhalt hat, wird
mithilfe von include eingebettet-->
<%@include file="menueEingabeWebSite.jsp" %>
</span>
</div>
<div class= "box3">
<span class="font4">

13.3 Eingabe von Objekten der Klasse WebSite

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

<!--Die Daten des Formulars werden mit GET an das Servlet


eingabeWebSiteServlet.java und anschliessend an
eingabeWebSiteBild.jsp weitergesendet-->
<form name=""
action="<%=request.getContextPath()%>/eingabeWebSite"
method="GET">
<table align="center" valign="middle">
<!--Sollten Sie auf den Button Text hinzufuegen geklickt haben,
werden die Texte und Formatierungen im Servlet einer ArrayList
hinzugefuegt, die hier wieder ausgelesen wird.-->
<c:forEach var="textFormatierungList"
items="${textFormatierungList}">
<c:forEach var="text" items="${textFormatierungList.text}">
<tr>
<td>Text</td>
<td><c:out value="${text.name}" /></td>
<td>&nbsp</td>
</tr>
</c:forEach>
<tr>
<td>Formatierung</td>
<td><c:out value="${textFormatierungList.name}" /></td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
</c:forEach>
<tr>
<td>Text</td>
<td>
<!--Eingabefeld fuer Texte-->
<input type="text" name="TextName" value="">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>
Formatierung
</td>
<td>
<!--Hier werden alle vorhandenen Formatierungen ausgelesen,
die den Texten hinzugefuegt werden koennen.-->

265

13 Unser Content-Management-System

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

<select name="FormatierungTextSelect" >


<c:forEach var="formatierung" items="${formatierung}">
<option value="<c:out value='${formatierung.name}'/>">
<c:out value="${formatierung.name}" />
</option>
</c:forEach>
</select>
</td>
<td>
&nbsp&nbsp&nbsp
<!--Wollen Sie mehrere Textfelder hinzufuegen klicken Sie
auf diesen Button-->
<input type="submit" name="Text"
value="Text hinzuf&uuml;gen" class="button" />
</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<!--Klicken Sie auf den Button Weiter gelangen Sie zum Formular
fuer die Eingabe von Bildern-->
<input type="submit" name="WeiterText"
value="Weiter" class="button" />
</td>
</tr>
</table>
</form>
</span>
</div>
</body>
</html>

Listing 13.8: eingabeWebSiteText.jsp

13.3.3 Eingabe von Bildern


Im folgenden Schritt fgen wir Bilder ein. Im Formular knnen Sie sowohl den Namen als auch
den Pfad des Bildes eingeben:

266

13.3 Eingabe von Objekten der Klasse WebSite

Abbildung 13.5: Eingabeformular fr Bilder


Bei den Bildern besteht auch die Mglichkeit entweder mehrere Bilder oder nur ein Bild der
WebSite hinzufgen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>Eingabe Bild</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>
<div class= "box2">
<span class="menu">
<!--Die Datei, die die Menueleiste zum Inhalt hat, wird
mithilfe der Direktive include eingebettet.-->
<%@include file="menueEingabeWebSite.jsp" %>
</span>
</div>
<div class= "box3">
<span class="font4">
<!--Die Daten werden weitergeschickt, zuerst an das Servlet
und anschliessend an das eingabeWebSitePdf.jsp-->
<form name=""
action="<%=request.getContextPath()%>/eingabeWebSite"
method="GET">

267

13 Unser Content-Management-System

<table align="center" valign="middle">

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

<!--Sollten Sie auf den Button Bild hinzufuegen geklickt haben,


werden die Daten der Bilder im Servlet einer ArrayList
hinzugefuegt, die hier wieder ausgelesen wird.-->
<c:forEach var="bildList" items="${bildList}">
<tr>
<td>Bild</td>
<td><c:out value="${bildList.name}" /></td>
<td>&nbsp</td>
</tr>
<tr>
<td>Pfad</td>
<td><c:out value="${bildList.pfad}" /></td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
</c:forEach>
<tr>
<td>Bild</td>
<td>
<input type="text" name="BildName" value="">
</td>
</tr>
<tr>
<td>Pfad</td>
<td>
<input type="text" name="BildPfad" value="">
</td>
<td>&nbsp&nbsp&nbsp
<!--Wollen Sie mehrere Bilder einfuegen, klicken Sie
bitte auf diesen Button.-->
<input type="submit" name="Bild"
value="Bild hinzuf&uuml;gen" class="button" />
</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr
<tr>
<td colspan="3" align="center">

268

13.3 Eingabe von Objekten der Klasse WebSite

82
83
84
85
86
87
88
89
90
91
92
93

<!--Klicken Sie auf den Button Weiter, gelangen Sie


zum naechsten Eingabeformular eingabeWebSitePdf.jsp-->
<input type="submit" name="WeiterBild" value="Weiter" class="button" />
</td>
</tr>
</table>
</form>
</span>
</div>
</body>
</html>
Listing 13.9: eingabeWebSiteBild.jsp

13.3.4 Eingabe von PDFs


Last, but not least fgen wir unserer WebSite noch PDFs hinzu, wobei zwei Felder auszufllen sind, nmlich das Feld Name und das Feld Pfad. Da dies das letzte Eingabeformular fr
unsere WebSite ist, gibt es hier keinen Button Weiter, sondern einen Button Eingabe, der den
Speichervorgang abschliet.

Abbildung 13.6: Eingabeformular fr PDFs


Das eingabeWebSitePdf.jsp unterscheidet sich vom eingabeWebSiteBild.jsp nur durch den Button
Eingabe, der alle Daten zum entsprechenden Servlet sendet, das dann alle Daten in der Datenbank
speichert.

1
2
3
4
5
6
7

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>

269

13 Unser Content-Management-System

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

270

<link rel="stylesheet" href="Styles/stil.css" type="text/css">


<title>Eingabe PDF</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>
<div class= "box2">
<span class="menu">
<!--Die Datei, die die Menueleist zum Inhalt hat, wird
mithilfe der Direktive include eingebettet.-->
<%@include file="menueEingabeWebSite.jsp" %>
</span>
</div>
<div class= "box3">
<span class="font4">
<!--Die Daten werden an das eingabeWebSiteServlet.java
zur Verarbeitung gesendet-->
<form name=""
action="<%=request.getContextPath()%>/eingabeWebSite"
method="GET">
<table align="center" valign="middle">
<!--Sollten Sie auf den Button PDF hinzufuegen geklickt haben,
werden die Daten der FDFs im Servlet einer ArrayList
hinzugefuegt, die hier wieder ausgelesen wird.-->
<c:forEach var="pdfList" items="${pdfList}">
<tr>
<td>Pdf</td>
<td><c:out value="${pdfList.name}" /></td>
<td>&nbsp</td>
</tr>
<tr>
<td>Pfad</td>
<td><c:out value="${pdfList.pfad}" /></td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
</c:forEach>
<tr>
<td>PDF</td>
<td><input type="text" name="PdfName" value=""></td>

13.3 Eingabe von Objekten der Klasse WebSite

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

<td>&nbsp</td>
</tr>
<tr>
<td>Pfad</td>
<td><input type="text" name="PdfPfad" value=""></td>
<td>&nbsp&nbsp&nbsp
<!--Wollen Sie mehrere PDFs einfuegen, klicken Sie
bitte auf diesen Button.-->
<input type="submit" name="Pdf"
value="Pdf hinzuf&uuml;gen" class="button" />
</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<!--Mit dem Klicken auf den Button Eingabe wird das
Speichern der WebSite und seinen Daten abgeschlossen.-->
<input type="submit" name="Eingabe"
value="Eingabe" class="button" />
</td>
</tr>
</table>
</form>
</span>
</div>
</body>
</html>
Listing 13.10: eingabeWebSitePdf.jsp

13.3.5 Das Eingabe-Servlet


Die Daten aus unseren 4 Eingabeformularen werden an unten stehendes Servlet gesendet, dort
werden die Daten weiterverarbeitet und wieder an die entsprechenden Formulare zurckgesendet.
Bevor wir allerdings unser Servlet verwenden knnen, mssen wir es in die web.xml eintragen
und der entsprechende Eintrag muss wie folgt aussehen:

1
2
3

<servlet>
<servlet-name>eingabeWebSite</servlet-name>
<servlet-class>Servlets.eingabeWebSiteServlet</servlet-class>

271

13 Unser Content-Management-System

4
5
6
7
8
9

<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>eingabeWebSite</servlet-name>
<url-pattern>/eingabeWebSite</url-pattern>
</servlet-mapping>
Listing 13.11: Eintrag des Servlets in die web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

package Servlets;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
java.io.IOException;
java.util.ArrayList;
java.util.HashMap;
java.util.Map;
javax.servlet.http.HttpSession;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.ServletException;

public class eingabeWebSiteServlet extends HttpServlet {

272

protected void doGet(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
/*Sollte das Session-Attribut errors nicht leer sein,
bitte entsprechende Session lschen.*/
request.getSession().removeAttribute("errors");
/*Die folgende HashMap soll Fehlermeldungen speichern.*/
Map errors = new HashMap();
/*Wir deklarieren alle Variablen, die wir fr das gesamte
Servlet brauchen*/
String linkPfad = null;
String link = null;
String formatierungText = null;
String textName = null;
String bildText;
String bildPfad;

13.3 Eingabe von Objekten der Klasse WebSite

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

String pdf;
String pdfPfad;
String reihenfolge;
String ebene;
Link linkNeu = new Link();
ArrayList<Text> textList = new ArrayList<Text>();
ArrayList<Formatierung> textFormatierungList
= new ArrayList<Formatierung>();
ArrayList<Bild> bildList = new ArrayList<Bild>();
ArrayList<PDF> pdfList = new ArrayList<PDF>();
ArrayList<Text> arrayListText = new ArrayList<Text>();
ArrayList<Bild> arrayListBild = new ArrayList<Bild>();
ArrayList<PDF> arrayListPdf = new ArrayList<PDF>();
/*Wurde im Formular eingabeWebSiteLink.jsp auf den Button
WeiterLink geklickt, wird unten stehender Ausdruck wahr.*/
if (request.getParameter("WeiterLink")!= null){
//Wir berprfen, ob in dem Feld Link ein Wert steht
if (request.getParameter("Link")!= null
&& request.getParameter("Link").length()>0){
link = request.getParameter("Link");
/*Sollte im Feld Linkname nichts eingegeben worden sein,
wird der HashMap errors eine Fehlermeldung hinzugefgt.*/
} else{
errors.put("link", "Link fehlt!");
System.out.println("Link fehlt!");
}
//Wir berprfen, ob in dem Feld Reihenfolge ein Wert steht.
if (request.getParameter("Reihenfolge")!= null
&& request.getParameter("Reihenfolge").length()>0){
/*Fr den Fall, dass das Attribut reihenfolge nicht leer ist,
soll das entsprechende Session-Attribut gelscht werden.*/
request.getSession().removeAttribute("reihenfolge");
/*Ist etwas in dem Feld Reihenfolge eingegeben worden, soll
ein Session-Attribut mit Namen reihenfolge gesetzt werden.*/
reihenfolge = request.getParameter("Reihenfolge");
request.getSession().setAttribute("reihenfolge", reihenfolge);
/*Sollte im Feld Reihenfolge nichts eingegeben worden sein,
wird der HashMap errors eine Fehlermeldung hinzugefgt.*/
} else{
errors.put("reihenfolge", "Reihenfolge fehlt!");
System.out.println("Reihenfolge fehlt!");
}

273

13 Unser Content-Management-System

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

274

/*Sollte der HashMap Elemente hinzugefgt worden sein,*/


if(errors.size()> 0){
request.getSession().setAttribute("errors", errors);
/*werden die Daten zurckgeschickt.*/
request.getRequestDispatcher("eingabeWebSiteLink.jsp").
forward(request, response);
}else{
//alte Session-Attribute lschen
request.getSession().removeAttribute("linkNeu");
request.getSession().removeAttribute("textFormatierungList");
request.getSession().removeAttribute("bildList");
request.getSession().removeAttribute("pdfList");
request.getSession().removeAttribute("ebene");
//Neuer Link, der der Session als Attribut bergeben wird.
linkNeu = new Link(link);
request.getSession().setAttribute("linkNeu", linkNeu);
//Neue Nummer der Ebene
ebene = request.getParameter("Ebene");
request.getSession().setAttribute("ebene", ebene);

//zu dieser Datei werden die Daten weitergeschickt


request.getRequestDispatcher("eingabeWebSiteText.jsp").
forward(request, response);

/*Wurde im Formular eingabeWebSiteText.jsp auf den Button


Text einfgen geklickt, wird unten stehender Ausdruck wahr.*/
}else if(request.getParameter("Text")!=null){
/*Es wird ein neues Textobjekt instanziiert,*/
Text t = new Text(request.getParameter("TextName"));
/*einer ArrayList bergeben*/
textList.add(t);
/*und anschliessend wird ein neues Formatierungsobjekt erstellt.*/
Formatierung f = new Formatierung
(request.getParameter("FormatierungTextSelect"), textList);
/*Sollte bereits eine ArrayList fr Formatierungen existieren,*/
if(request.getSession().getAttribute
("textFormatierungList") != null){

13.3 Eingabe von Objekten der Klasse WebSite

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

/*wird dieser das Formatierungsobjekt f hinzugefgt*/


textFormatierungList = (ArrayList<Formatierung>)request.
getSession().getAttribute("textFormatierungList");
textFormatierungList.add(f);
/*und dann wird das Formatierungsobjekt wieder der Session
als Attribut bergeben.*/
request.getSession().setAttribute
("textFormatierungList", textFormatierungList);
/*Die Daten werden in diesem Fall wieder zurckgesendet*/
request.getRequestDispatcher("eingabeWebSiteText.jsp").
forward(request, response);
/*Sollte es kein Session-Attribut textFormatierungList geben,
wird der textFormatierungList das erste Element hinzugefgt*/
} else{
textFormatierungList.add(f);
/*und dann wieder der Session als Attribut bergeben.*/
request.getSession().setAttribute
("textFormatierungList", textFormatierungList);

/*Die Daten werden wieder zurckgesendet.*/


request.getRequestDispatcher("eingabeWebSiteText.jsp").
forward(request, response);

/*Wurde im Formular eingabeWebSiteText.jsp auf den Button


WeiterText geklickt, wird unten stehenden Ausdruck wahr.*/
}else if(request.getParameter("WeiterText")!= null){
/*Ist das Feld TextName nicht leer, wird ein neues Textobjekt
erstellt, einer ArrayList bergeben und anschlieend
wird ein Formatierungsobjekt erstellt.*/
if (request.getParameter("TextName")!= null
&& request.getParameter("TextName").length()>0){
Text t = new Text(request.getParameter("TextName"));
textList.add(t);
Formatierung f = new Formatierung
(request.getParameter("FormatierungTextSelect"), textList);
/*Gibt es bereits ein Session-Attribut mit Namen
textFormatierungList wird dieser das soeben
erstellte Formatierungsobjekt bergeben.*/
if(request.getSession().getAttribute
("textFormatierungList") != null){
textFormatierungList = (ArrayList<Formatierung>)request.

275

13 Unser Content-Management-System

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

276

getSession().getAttribute("textFormatierungList");
textFormatierungList.add(f);
/*Das Session-Attribut wird gesetzt*/
request.getSession().setAttribute
("textFormatierungList", textFormatierungList);
/*Die Daten werden zum eingabeWebSiteBild.jsp weitergesendet.*/
request.getRequestDispatcher("eingabeWebSiteBild.jsp").
forward(request, response);
/*Sollte es ein Session-Attribut mit Namen textFormatierungList
nicht geben, wird der ArrayList textFormatierungList ein erstes
Element Formatierung f bergeben und
anschlieend wird das Session-Attribut gesetzt.*/
} else{
textFormatierungList.add(f);
request.getSession().setAttribute
("textFormatierungList", textFormatierungList);

/*Die Daten werden zum Formular eingabeWebSiteBild.jsp gesendet.*/


request.getRequestDispatcher("eingabeWebSiteBild.jsp").
forward(request, response);

/*Sollte das Feld TextName leer sein, geht es zu


folgendem Formular:*/
} else{
request.getRequestDispatcher("eingabeWebSiteBild.jsp").
forward(request, response);
}
/*Wurde im Formular eingabeWebSiteBild.jsp auf den Button
Bild hinzufgen geklickt, tritt der folgende else-Zweig ein.*/
}else if(request.getParameter("Bild")!=null){
/*Wir instanziieren ein Objekt der Klasse Bild mit Werten, die
aus dem Formular gesendet wurden.*/
Bild bild = new Bild
(request.getParameter("BildName"),
request.getParameter("BildPfad"));
/*Sollte eine ArrayList<Bild> bildList existieren,*/
if(request.getSession().getAttribute("bildList") != null){
/*lesen Sie diese aus dem Session-Attribut aus*/
bildList = (ArrayList<Bild>)request.getSession().
getAttribute("bildList");

13.3 Eingabe von Objekten der Klasse WebSite

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

/*und fgen das neue Bild dieser ArrayList<Bild> hinzu.*/


bildList.add(bild);
request.getSession().setAttribute("bildList", bildList);
request.getRequestDispatcher("eingabeWebSiteBild.jsp").
forward(request, response);
/*Ansonsten fgen Sie dieser ArrayList<Bild> bildList
das erste Bild hinzu.*/
}else{
bildList.add(bild);
request.getSession().setAttribute("bildList", bildList);
request.getRequestDispatcher("eingabeWebSiteBild.jsp").
forward(request, response);
}
/*Wurde auf den Button Weiter im eingabeWebSiteBild.jsp geklickt*/
}else if(request.getParameter("WeiterBild")!= null){
/*und wurde sowohl in das Feld BildName als auch in das
Feld BildPfad etwas eingegeben,*/
if (request.getParameter("BildName")!= null
&& request.getParameter("BildName").length()>0
|| request.getParameter("BildPfad")!= null
&& request.getParameter("BildPfad").length()>0){
/*wird ein neues Bild mit diesen Werten instanziiert.*/
Bild bild = new Bild
(request.getParameter("BildName"), request.
getParameter("BildPfad"));
/*Sollte bereits der ArrayList<Bild> bildList ein Element
hinzugefgt worden sein,*/
if(request.getSession().getAttribute("bildList") != null){
/*lesen Sie diese bildList aus der Session aus*/
bildList = (ArrayList<Bild>)request.getSession().
getAttribute("bildList");
/*und fgen ihr das neue Objekt der Klasse Bild hinzu.*/
bildList.add(bild);
request.getSession().setAttribute("bildList", bildList);
request.getRequestDispatcher("eingabeWebSitePdf.jsp").
forward(request, response);
/*Ansonsten fgen Sie der ArrayList<Bild> bildList das
erste Objekt der Klasse Bild hinzu.*/
}else{
bildList.add(bild);
request.getSession().setAttribute("bildList", bildList);

277

13 Unser Content-Management-System

285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333

278

request.getRequestDispatcher("eingabeWebSitePdf.jsp").
forward(request, response);

} else{
request.getRequestDispatcher("eingabeWebSitePdf.jsp").
forward(request, response);
}
/*Wurde im eingabeWebSitePdf.jsp auf den Button PDF hinzufgen
geklickt, erstellen Sie mit den Werten aus dem Formular ein neues
Objekt der Klasse PDF.*/
}else if(request.getParameter("Pdf")!=null){
PDF neuesPdf = new PDF
(request.getParameter("PdfName"), request.
getParameter("PdfPfad"));
/*Existiert bereits eine ArrayList<PDF> pdfList, wird
dieser das neue PDF hinzugefgt.*/
if(request.getSession().getAttribute("pdfList") != null){
pdfList = (ArrayList)request.getSession().
getAttribute("pdfList");
pdfList.add(neuesPdf);
request.getSession().setAttribute("pdfList", pdfList);
request.getRequestDispatcher("eingabeWebSitePdf.jsp").
forward(request, response);
/*Sollte sie nicht existieren, wird der pdfList das erste
PDF hinzugefgt.*/
}else{
pdfList.add(neuesPdf);
request.getSession().setAttribute("pdfList", pdfList);
request.getRequestDispatcher("eingabeWebSitePdf.jsp").
forward(request, response);
}
/*Wurde im Formular eingabeWebSitePdf.jsp auf den Button
Eingabe geklickt*/
}else if(request.getParameter("Eingabe") != null){
/*und wurde sowohl die Felder PdfName als auch PdfPfad
ausgefllt, wird ein neues PDF mit diesen Daten instanziiert.*/
if (request.getParameter("PdfName")!= null
&& request.getParameter("PdfName").length()>0
||request.getParameter("PdfPfad")!= null
&& request.getParameter("PdfPfad").length()>0){
PDF neuesPdf = new PDF
(request.getParameter("PdfName"), request.

13.3 Eingabe von Objekten der Klasse WebSite

334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382

getParameter("PdfPfad"));
/*Sollte es noch keine pdfList in der Session geben,
fgen Sie ihr das erste PDF hinzu.*/
if(request.getSession().getAttribute("pdfList")== null){
pdfList.add(neuesPdf);
request.getSession().setAttribute("pdfList", pdfList);
/*Andernfalls fgen Sie der pdfList aus der Session ein
PDF hinzu.*/
}else{
pdfList = (ArrayList<PDF>)request.getSession().
getAttribute("pdfList");
pdfList.add(neuesPdf);
request.getSession().setAttribute("pdfList", pdfList);
}
//Wir instanziieren ein neues Objekt der Klasse WebSiteDaten,
WebSiteDaten webDa = new WebSiteDaten();
/*wir lesen alle Daten aus der Session aus */
linkNeu = (Link)request.getSession().getAttribute("linkNeu");
textFormatierungList = (ArrayList<Formatierung>)request.
getSession().getAttribute("textFormatierungList");
for(Formatierung f: textFormatierungList){
System.out.println("Format: "+ f.getName());
}
bildList = (ArrayList<Bild>)request.getSession().
getAttribute("bildList");
reihenfolge = (String)request.getSession().
getAttribute("reihenfolge");
pdfList = (ArrayList<PDF>)request.getSession().
getAttribute("pdfList");
System.out.println("reihenfolge oben " + reihenfolge);
ebene = (String)request.getSession().getAttribute("ebene");
/*und speichern unsere Daten, indem wir sie als Parameter
der Methode addWebSite() bergeben*/
webDa.addWebSite
(linkNeu, textFormatierungList, bildList,
pdfList, reihenfolge, ebene, request);

request.getRequestDispatcher("eingabeWebSiteLink.jsp").
forward(request, response);
/*Sollten keine Daten in die Felder PdfName und PdfPfad
eingegeben worden sein, werden die Daten direkt

279

13 Unser Content-Management-System

383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416

ausgelesen und gespeichert.*/


} else{
WebSiteDaten webDa = new WebSiteDaten();
linkNeu = (Link)request.getSession().getAttribute("linkNeu");
textFormatierungList = (ArrayList<Formatierung>)request.
getSession().getAttribute("textFormatierungList");
bildList = (ArrayList<Bild>)request.getSession().
getAttribute("bildList");
reihenfolge = (String)request.getSession().
getAttribute("reihenfolge");
pdfList = (ArrayList<PDF>)request.getSession().
getAttribute("pdfList");
System.out.println("reihenfolge unten " + reihenfolge);
ebene = (String)request.getSession().getAttribute("ebene");

webDa.addWebSite
(linkNeu, textFormatierungList, bildList,
pdfList, reihenfolge, ebene, request);
request.getRequestDispatcher("eingabeWebSiteLink.jsp").
forward(request, response);

}else if(request.getParameter("eWeb") != null){


response.sendRedirect
(request.getContextPath()+ "/eingabeWebSiteLink.jsp");
}

protected void doPost(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

Listing 13.12: eingabeWebSiteServlet.java

13.4 Ausgabe von Objekten der Klasse WebSite


Nachdem wir Daten eingegeben haben, wollen wir unsere Objekte der Klasse WebSite im Browser
ausgeben. Unser Internetauftritt sieht wie folgt aus:

280

13.4 Ausgabe von Objekten der Klasse WebSite

Abbildung 13.7: Ausgabe unserer Daten


Unser Internetauftritt besteht aus drei Teilen: In der oberen Menleiste werden alle Links ausgelesen, die keinen Eintrag im Feld Ebene haben. Dies geschieht mit der Methode auslesenLinkErste()
der Klasse WebSiteDaten.java. Links werden mithilfe der Methoden auslesenLinkReihenfolge()
und auslesenLinkZweite() die Elemente der linken Menleiste ausgelesen. Und in der Mitte rechts
lesen wir die dazugehrigen Inhalte aus.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>Content-Management-System</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>
<span class= "variablebox">

281

13 Unser Content-Management-System

<!--Die obere Menueleiste befindet sich in einer Aufzaehlung. -->


<ul class="list">

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

<!--Die Elemente der oberen Menueleiste werden in der Klasse


WebSiteFilter.java ausgelesen.-->
<c:forEach var="link" items="${webSiteMenu}">
<li>
<!--Klicken Sie auf einen Link der oberen Menueleiste, wird
das JSP mit GET an das Servlet ausgabeWebSiteServlet.java
weitergeleitet.-->
<a href="
<%=request.getContextPath()%>/ausgabe?SeitenOben=<c:out value='${link.
name}' />">
<c:out value="${link.name}" />
</a>
</li>
</c:forEach>
</ul>
</span>
<span class= "box2">
<span class="menu">
<!--Klicken Sie auf einen Link in der oberen Leiste, werden im
ausgabeWebSiteServlet.java die dazugehoerigen Hyperlinks fuer
die linke Menueleiste ausgelesen.-->
<c:forEach var="linkLinks" items="${webSiteMenuLinks}">
<a href="
<%=request.getContextPath()%>/ausgabe?Seiten=<c:out value='${linkLinks.
name}' />">
<c:out value="${linkLinks.name}" />
</a>
</c:forEach>
</span>
</span>
<span class= "box3">
<!--Im Servlet wird mit auslesenText() der Text und die
dazugehoerigen Formatierungen ausgelesen.-->
<c:forEach var="webSiteTextFormatierung"
items="${webSiteTextFormatierung}">
<div class="${webSiteTextFormatierung.name}">
<c:forEach var="webSiteTextFormatierungText"
items="${webSiteTextFormatierung.text}">
<c:out value="${webSiteTextFormatierungText.name}" />
</c:forEach>

282

13.4 Ausgabe von Objekten der Klasse WebSite

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

</div>
</c:forEach>
<!--Im Servlet werden die Bilder und die PDFs mit
auslesenEinzeln() aus der Datenbank ausgelesen.-->
<c:forEach var="webSiteBild" items="${webSiteBild}">
<img src="<c:out value='${webSiteBild.pfad}' />"
alt="<c:out value='${webSiteBild.name}' />">
</c:forEach>
<c:forEach var="pdf" items="${webSitePdf}">
<div class="menub">
<a href="<c:out value='${pdf.pfad}' />">
<c:out value="${pdf.name}" />
</a>
</div>
</c:forEach>
</span>
</body>
</html>
Listing 13.13: ausgeben.jsp

Als Nchstes bentigen wir einen Filter, der es uns ermglicht bereits beim ersten Aufrufen
der Seite, Inhalt fr die Seite Home auszulesen. Wir erinnern uns: Sie knnen nur Daten zum
Servlet senden, wenn ein Request ausgefhrt wird, beim ersten Aufrufen einer Seite existiert nur
ein Response, also die Antwort vom Server an den Client. Der Filter lst dieses Problem (vgl.
Kapitel Filter).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

package Eingang;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
java.io.IOException;
java.util.ArrayList;
javax.servlet.Filter;
javax.servlet.FilterChain;
javax.servlet.FilterConfig;
javax.servlet.ServletContext;
javax.servlet.ServletException;
javax.servlet.ServletRequest;
javax.servlet.ServletResponse;
javax.servlet.http.HttpServletRequest;

283

13 Unser Content-Management-System

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

public class WebSiteFilter implements Filter {


private FilterConfig filterConfig = null;
/*Die init()-Methode wird bei der Instanziierung des
Filters aufgerufen, und es wird ber das FilterConfig und
die Methode getServletContext() einen Zugriff auf
den ServletContext ermglicht.*/
public void init(FilterConfig filterConfig) throws
ServletException {
this.filterConfig = filterConfig;
}
/*In der doFilter()-Methode werden die Aufgaben
des Filters durchgefhrt.*/
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
/*Das ServletRequest request muss in ein
HttpServletRequest gecastet werden, da
es sich um eine Webanwendung handelt.*/
HttpServletRequest req = (HttpServletRequest) request;
/*Sollte das webSiteMenu bereits existieren, soll es
aus der Session gelscht werden.*/
req.getSession().removeAttribute("webSiteMenu");
WebSiteDaten webSiteDatenMenu = new WebSiteDaten();
/*Die Daten fr die obere Menleiste wird ausgelesen.*/
ArrayList<Link> webSiteMenu = webSiteDatenMenu.auslesenLinkErste(req);
/*Sollte die Seite ausgeben.jsp das erste Mal aufgerufen
werden und sollte noch niemand auf einen Link geklickt haben,*/
if(request.getParameter("SeitenOben") == null
|| request.getParameter("Seiten") == null){
/*werden die Daten fr Home ausgelesen:*/
WebSiteDaten webSite = new WebSiteDaten();
ArrayList<Formatierung> webSiteTextFormatierung =
webSite.auslesenText("Home", req);
WebSite ws = webSite.auslesenEinzeln("Home", req);
ArrayList<Bild> webSiteBild = ws.getBild();
ArrayList<PDF> webSitePdf = ws.getPdf();
/*Die ausgelesen Daten werden der Session bergeben.*/
req.getSession().setAttribute
("webSiteTextFormatierung", webSiteTextFormatierung);

284

13.4 Ausgabe von Objekten der Klasse WebSite

70
71
72
73
74
75
76
77
78
79
80
81
82
83

req.getSession().setAttribute("webSiteBild", webSiteBild);
req.getSession().setAttribute("webSitePdf", webSitePdf);

/*Die Daten fr die obere Menleiste wird der Session bergeben.*/


req.getSession().setAttribute("webSiteMenu", webSiteMenu);
}

chain.doFilter(request, response);

public void destroy() {


}

Listing 13.14: WebSiteFilter.java


Vergessen wir nicht, den Filter in die web.xml einzutragen.

1
2
3
4
5
6
7
8

<filter>
<filter-name>WebSiteFilter</filter-name>
<filter-class>Eingang.WebSiteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>WebSiteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Listing 13.15: Eintrag fr den WebSiteFilter in der web.xml

Die Daten aus dem ausgeben.jsp werden an das ausgabeWebSiteServlet.java gesendet. Im Servlet
werden die Daten aus der Datenbank ausgelesen und zurck an das JSP gesendet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package Servlets;
import
import
import
import
import
import
import
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
java.io.IOException;
java.util.ArrayList;
java.util.Collection;
javax.servlet.http.HttpSession;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;

285

13 Unser Content-Management-System

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
public class ausgabeWebSiteServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
/*Wird im ausgeben.jsp auf einen Hyperlink in der oberen
Menleiste geklickt, wird folgender Ausdruck wahr.*/
if(request.getParameter("SeitenOben") != null ){
/*Existieren bereits Attribute sollen diese aus der Session
entfernt werden.*/
request.getSession().removeAttribute("seiten");
request.getSession().removeAttribute("webSiteTextFormatierung");
request.getSession().removeAttribute("webSiteBild");
request.getSession().removeAttribute("webSitePdf");
String seitenOben = request.getParameter("SeitenOben");
/*Es werden die Daten aus der Datenbank ausgelesen:*/
WebSiteDaten webSite = new WebSiteDaten();
String reihenfolgeLinks = webSite.
auslesenLinkReihenfolge(seitenOben, request);
ArrayList<Link> webSiteMenuLinks = webSite.
auslesenLinkZweite(reihenfolgeLinks, request);
ArrayList<Formatierung> webSiteTextFormatierung = webSite.
auslesenText(seitenOben, request);
WebSite ws = webSite.auslesenEinzeln(seitenOben, request);
ArrayList<Bild> webSiteBild = ws.getBild();
ArrayList<PDF> webSitePdf = ws.getPdf();

/*Die ausgelesenen Daten werden der Session als Attribute


bergeben:*/
request.getSession().setAttribute
("webSiteMenuLinks", webSiteMenuLinks);
request.getSession().setAttribute
("webSiteTextFormatierung", webSiteTextFormatierung);
request.getSession().setAttribute("webSiteBild", webSiteBild);
request.getSession().setAttribute("webSitePdf", webSitePdf);
request.getRequestDispatcher("ausgeben.jsp").
forward(request, response);

/*Wird in der linken Menleiste in der ausgeben.jsp


auf einen Link geklickt, wird folgender if-Zweig durchgefhrt.*/
else if(request.getParameter("Seiten")!= null ){

286

13.4 Ausgabe von Objekten der Klasse WebSite

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

request.getSession().removeAttribute("webSiteTextFormatierung");
request.getSession().removeAttribute("webSiteBild");
request.getSession().removeAttribute("webSitePdf");
String seiten = request.getParameter("Seiten");
WebSiteDaten webSite = new WebSiteDaten();
ArrayList<Formatierung> webSiteTextFormatierung =
webSite.auslesenText(seiten, request);
WebSite ws = webSite.auslesenEinzeln(seiten, request);
ArrayList<Bild> webSiteBild = ws.getBild();
ArrayList<PDF> webSitePdf = ws.getPdf();

request.getSession().setAttribute
("webSiteTextFormatierung", webSiteTextFormatierung);
request.getSession().setAttribute("webSiteBild", webSiteBild);
request.getSession().setAttribute("webSitePdf", webSitePdf);
request.getRequestDispatcher("ausgeben.jsp").
forward(request, response);

protected void doPost(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

Listing 13.16: ausgabeWebSiteServlet.java


Das entsprechende Servlet-Mapping in der web.xml sieht wie folgt aus:

1
2
3
4
5
6
7
8
9

<servlet>
<servlet-name>ausgabe</servlet-name>
<servlet-class>Servlets.ausgabeWebSiteServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ausgabe</servlet-name>
<url-pattern>/ausgabe</url-pattern>
</servlet-mapping>

Listing 13.17: Eintrag fr das ausgabeWebSiteServlet.java in der web.xml

287

13 Unser Content-Management-System

13.5 Lschen von Objekten der Klasse WebSite


Wie Lschen wir die Objekte der Klasse WebSite wieder? Wir erstellen eine Auswahlliste, die
alle Links in alphabetischer Reihenfolge anzeigt. Sie knnen einen Link auswhlen, auf lschen
klicken und die WebSite wird gelscht, falls keine untergeordnete WebSite existiert. Dies ist bei
der WebSite Produkte der Fall: Es existieren noch zwei, nmlich die WebSite Bcher und DVD.
Sollten Sie versuchen dieses Objekt der Klasse WebSite zu lschen, wird eine Fehlermeldung
ausgegeben.
Betrachten wir alle dafr notwendigen Dateien: Hier eine Abbildung des entsprechenden Auswahlformulars, das es Ihnen ermglicht, Objekte der Klasse WebSite zu lschen:

Abbildung 13.8: Lschen


In diesem JSP werden die zu lschenden Links in der Auswahlliste ausgelesen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>Webseite l&ouml;schen</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>
<div class= "box2">
<span class="menu">

288

<%@include file="menueEingabeWebSite.jsp"%>
</span>
</div>
<div class= "box3">

13.5 Lschen von Objekten der Klasse WebSite

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

<span class="font4">
<!--Sollte ein Objekt der Klasse WebSite noch eine Unterkategorie
enthalten, d.h. ein Objekt der Klasse WebSite, die eine identische
Reihenfolge besitzt, aber einer Ebene, die nicht leer ist, wird
eine Fehlermeldung ausgegeben. -->
<c:if test="${meldung != null}">
<c:out value="${meldung}" />
<br>
<c:out value="${param.Link}"/>
<br><br>
</c:if>
<!--Das Formular wird zum loeschenWebSiteServlet gesendet.-->
<form name=""
action="<%=request.getContextPath()%>/loeschenWebSite"
method="GET">
<table align="center" valign="middle">
<tr>
<td>
Link
</td>
<td>
<!--Es werden im Servlet alle Links alphabtisch
ausgelesen und hier im JSP ausgegeben.-->
<select name="Link" >
<c:forEach var="arrayListLink" items="${arrayListLink}">
<option value="<c:out value='${arrayListLink.name}' />">
<c:out value="${arrayListLink.name}" />
</option>
</c:forEach>
</select>
</td>
<td>
&nbsp
</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<input type="submit" name="Loeschen"
value="L&ouml;schen" class="button" />
</td>
</tr>

289

13 Unser Content-Management-System

</table>
</form>
</span>
</div>
</body>
</html>

71
72
73
74
75
76

Listing 13.18: loeschenWebSiteLink.jsp


Die Daten des JSP werden in unten stehendem Filter aus der Datenbank ausgelesen. Die Daten
werden nach jedem Lschen aktualisiert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

package Eingang;
import
import
import
import
import
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Link;
java.io.IOException;
java.util.ArrayList;
javax.servlet.Filter;
javax.servlet.FilterChain;
javax.servlet.FilterConfig;
javax.servlet.ServletException;
javax.servlet.ServletRequest;
javax.servlet.ServletResponse;
javax.servlet.http.HttpServletRequest;

public class LoeschenFilter implements Filter {

290

private FilterConfig filterConfig = null;


/*Die init()-Methode wird bei der Instanziierung des
Filters aufgerufen und es wird ber das FilterConfig und
die Methode getServletContext() einen Zugriff auf
den ServletContext ermglicht.*/
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
/*In der doFilter()-Methode werden die Aufgaben
des Filters durchgefhrt.*/
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
/*Das ServletRequest request muss in ein
HttpServletRequest gecastet werden, da
es sich um eine Webanwendung handelt.*/
HttpServletRequest req = (HttpServletRequest) request;

13.5 Lschen von Objekten der Klasse WebSite

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

/*Sollte das arrayListLink bereits existieren, soll es


aus der Session gelscht werden.*/
req.getSession().removeAttribute("arrayListLink");
/*Wir lesen hier die Links fr die Auswahlliste des
loeschenWebSiteLink.jsp aus.*/
WebSiteDaten wsd = new WebSiteDaten();
ArrayList<Link>arrayListLink = (ArrayList<Link>)wsd.auslesenLink(req);
req.getSession().setAttribute("arrayListLink", arrayListLink);
chain.doFilter(request, response);
}
public void destroy() {
}
}

Listing 13.19: LoeschenFilter.java

Wir registrieren unseren Filter in der web.xml mithilfe eines Filtermappings. Da unsere Daten
auch bei jedem response auf den neuesten Stand gebracht werden sollen, bentigen wir zustzlich
einen Eintrag <dispatcher>FORWARD</dispatcher>. Vergleichen Sie hierzu auch das Kapitel
Filter.

1
2
3
4
5
6
7
8
9

<filter>
<filter-name>LoeschenFilter</filter-name>
<filter-class>Eingang.LoeschenFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoeschenFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>

Listing 13.20: webLoeschenFilter.xml

Kommen wir jetzt zum eigentlichen Lschvorgang: Wir wollen verhindern die WebSite Produkte
zu lschen, da sie noch zwei untergeordnete WebSites enthlt. Versuchen wir es trotzdem, erhalten
wir folgende Fehlermeldung:

291

13 Unser Content-Management-System

Abbildung 13.9: Fehlermeldung


Wohingegen wir eine Erfolgsmeldung erhalten, sollten wir die WebSite DVD lschen:

Abbildung 13.10: Erfolgsmeldung


Die WebSite Produkte kann erst gelscht werden, wenn auch noch zustzlich das WebSite-Objekt
Bcher gelscht wurde. Sie bentigen eine if-Struktur, um dies umzusetzen. Schauen wir uns das
Servlet an, das uns diese Mglichkeiten zur Verfgung stellt:

1
2
3
4
5
6
7
8
9
10
11
12
13

package Servlets;
import
import
import
import
import
import
import
import
import
import
import

292

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Link;
Datenbankentwurf.WebSite;
java.io.IOException;
java.util.ArrayList;
java.util.List;
javax.servlet.http.HttpSession;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.ServletException;

13.5 Lschen von Objekten der Klasse WebSite

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

public class loeschenWebSiteServlet extends HttpServlet {


protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
ArrayList<Link> arrayListLink = new ArrayList();
/*Klicken Sie im eingabeWebSite.jsp auf den Hyperlink Loeschen,
der sich auf der linken Seite befindet, wird unten
stehender Ausdruck wahr.*/
if(request.getParameter("lWeb")!= null){
/*Fehlermeldung soll aus der Session gelscht werden.*/
request.getSession().removeAttribute("meldung");
/*Die Daten, die Sie in der Auswahlliste im Lschenformular
brauchen, wird im LoeschenFilter.java ausgelesen. Hier wird
zum loeschenWebSiteLink.jsp weitergeleitet.*/
request.getRequestDispatcher("loeschenWebSiteLink.jsp").
forward(request, response);
/*Klicken Sie im loeschenWebSiteLink.jsp auf den Button Loeschen
wird dieser Ausdruck wahr.*/
}if(request.getParameter("Loeschen") != null){
/*Fehlermeldung soll aus der Session gelscht werden.*/
request.getSession().removeAttribute("meldung");
/*Der Name des Links wird aus dem Formular ausgelesen,*/
String linkName = request.getParameter("Link");
WebSiteDaten wsd = new WebSiteDaten();
/*und die entsprechende WebSite und die reihenfolge und ebene
wird aus der Datenbank abgefragt.*/
WebSite w = wsd.auslesenEinzeln(linkName, request);
String reihenfolge = w.getReihenfolge();
String ebene = w.getEbene();
/*Hier wird festgestellt, wieviele Elemente mit der
reihenfolge und einer nicht leeren Ebene es gibt.*/
ArrayList<Link> l = (ArrayList<Link>)wsd.
auslesenLinkZweite(reihenfolge, request);
/*Sollte die Anzahl der Elemente mit der reihenfolge und einer
nicht leeren Ebene nicht 0 sein und die ausgelesene WebSite sollte
eine nicht leere Ebene haben, wird die WebSite gelscht.*/
if(l.size() != 0 && !ebene.equals("")){

293

13 Unser Content-Management-System

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

Link li = new Link(linkName);


wsd.deleteWebSite(li, request);
/*Die Erfolgsmeldung wird angelegt und der Session als
Attribut bergeben.*/
String meldung = new String("Dieser Link wurde erfolgreich gelscht: ");
request.getSession().setAttribute("meldung", meldung);
/*Die Daten werden zum loeschenWebSiteLink.jsp gesendet.*/
request.getRequestDispatcher("loeschenWebSiteLink.jsp").
forward(request, response);
/*Sollte die Anzahl der Elemente mit der reihenfolge und einer
nicht leeren Ebene 0 sein, wird die entsprechende WebSite
gelscht und eine Erfolgsmeldung zurck zum Formular gesendet.*/
} else if(l.size() == 0 ){
Link li = new Link(linkName);
wsd.deleteWebSite(li, request);
String meldung = new String("Dieser Link wurde erfolgreich gelscht: ");
request.getSession().setAttribute("meldung", meldung);
request.getRequestDispatcher("loeschenWebSiteLink.jsp").
forward(request, response);
/*Ansonsten wird, -wie im Falle der WebSite Produkte - solange
das Objekt WebSite noch untergeordnete WebSite-Objekte enthlt,
eine Fehlermeldung an das Lschenformular gesendet und das
Objekt kann nicht gelscht werden.*/
} else{
String meldung = new String("Dieser Link kann nicht gelscht werden: ");
request.getSession().setAttribute("meldung", meldung);
request.getRequestDispatcher("loeschenWebSiteLink.jsp").
forward(request, response);
}
}
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Listing 13.21: loeschenWebSiteServlet.java

Und denken Sie an den Eintrag fr das Servlet in der web.xml:

1
2

<servlet>
<servlet-name>loeschenWebSite</servlet-name>

294

13.6 ndern von Objekten der Klasse WebSite

3
4
5
6
7
8

<servlet-class>Servlets.loeschenWebSiteServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loeschenWebSite</servlet-name>
<url-pattern>/loeschenWebSite</url-pattern>
</servlet-mapping>
Listing 13.22: webLoeschen.xml

13.6 ndern von Objekten der Klasse WebSite


Nachdem wir die Daten fr unser WebSites eingegeben, wieder ausgelesen und gelscht haben,
wollen wir jetzt Daten ndern. Hierzu bentigen wir, hnlich wie bereits bei der Eingabe, mehrere Formularseiten. Unser erstes Formular ist das aendernWebSiteLink.jsp, in dem es folgende
Auswahlliste gibt, die Ihnen alle Links in alphabtischer Reihenfolge zur Auswahl vorgibt.

Abbildung 13.11: ndern


Unten stehend das dazugehrige aendernWebSiteLink.jsp, wobei Sie das Dokument, das mit der
Direktive Include eingebettet wird, weiter oben im Kapitel Eingabe von Objekten der Klasse
WebSite nden knnen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<!--Die CSS-Datei befindet sich im Ordner web/Styles-->
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>&Auml;ndern der WebSite</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>

295

13 Unser Content-Management-System

<div class= "box2">


<span class="menu">

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

<!--Die Datei, die die linke Menueleiste zum Inhalt hat,


wird mit der Direktive Include eingebunden.-->
<%@include file="menueEingabeWebSite.jsp"%>
</span>
</div>
<div class= "box3">
<span class="font4">
<!--Die Daten des Formulars werden zum aendernWebSiteServlet.java
mit GET gesendet.-->
<form name=""
action="<%=request.getContextPath()%>/aendernWebSite"
method="GET">
<table align="center" valign="middle">
<tr>
<td>
Link
</td>
<td>
<!--Es werden im Servlet alle Links alphabtisch
ausgelesen und hier im JSP ausgegeben.-->
<select name="Link" >
<c:forEach var="arrayListLink" items="${arrayListLink}">
<option value="<c:out value='${arrayListLink.name}' />">
<c:out value="${arrayListLink.name}" />
</option>
</c:forEach>
</select>
</td>
<td>
&nbsp
</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<!--Klicken Sie auf den Aendern-Button gelangen Sie zum
naechsten Formular aendernWebSiteLinkFolgende.jsp. -->
<input type="submit" name="Aendern"
value="&Auml;ndern" class="button" />

296

13.6 ndern von Objekten der Klasse WebSite

66
67
68
69
70
71
72
73

</td>
</tr>
</table>
</form>
</span>
</div>
</body>
</html>
Listing 13.23: aendernWebSiteLink.jsp

13.6.1 ndern des Hyperlinks, der Reihenfolge und der Ebene


Im ersten Schritt kann der Name des Links, die Reihenfolge und die Ebene gendert werden:
Klicken Sie auf den Button ndern im aendernWebSiteLink.jsp, nachdem Sie die zu verndernde
WebSite ausgewhlt haben, und Sie gelangen zu unten stehendem Formular. Wir ersetzen Bcher
durch Computer, die Reihenfolge 2 durch 3 und das Feld fr die Ebene leeren wir.

Abbildung 13.12: Formular Link-ndern


Hier das entsprechende JSP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>&Auml;ndern Link, Reihenfolge und Ebene</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>
<div class= "box2">

297

13 Unser Content-Management-System

<span class="menu">
<%@include file="menueEingabeWebSite.jsp"%>
</span>
</div>
<div class= "box3">
<span class="font4">

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

<!--Das Formular wird zum Servlet und anschliessend zum


aendernWebSiteText.jsp gesendet.-->
<form name=""
action="<%=request.getContextPath()%>/aendernWebSite"
method="GET">
<table align="center" valign="middle">
<tr>
<!--Es wird der Link, die Reihenfolge und die Ebene ausgegeben.-->
<td>Link</td>
<td>
<input type="text" name="Link" value="<c:out value='${linkAltName}'/>">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td>Reihenfolge</td>
<td><input type="text" name="Reihenfolge"
value="<c:out value='${reihenfolge}'/>" size="3">
<input type="text" name="Ebene"
value="<c:out value='${ebene}'/>" size="3">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<input type="submit" name="WeiterLink" value="Weiter" class="button" />
</td>
</tr>
</table>

298

13.6 ndern von Objekten der Klasse WebSite

65
66
67
68
69

</form>
</span>
</div>
</body>
</html>
Listing 13.24: aendernWebSiteLinkFolgende.jsp

13.6.2 ndern des Textes


Im zweiten Schritt ndern wir den Text: Wir werden unsere WebSite ndern, indem wir den
Textnamen durch TextComputer ersetzen und einen Text hinzufgen, und zwar den Text mit
Namen Zweiter Text und der Formatierung font1 . Schauen wir uns das Formular an, es wird
er passende Text zu unserer WebSite Bcher ausgegeben, den Sie ndern sollen:

Abbildung 13.13: Formular Text-ndern


Im folgenden nden Sie das aendernWebSiteText.jsp, das Ihnen das ndern von Text ermglicht:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>&Auml;ndern Text</title>
</head>
<body>
<div class="box1"><img src="Bilder/oben.jpg" width="800" height="100"></div>
<div class= "box2">
<span class="menu">
<%@include file="menueEingabeWebSite.jsp"%>
</span>
</div>

299

13 Unser Content-Management-System

<div class= "box3">


<span class="font4">
<form name=""
action="<%=request.getContextPath()%>/aendernWebSite"
method="GET">
<table align="center" valign="middle">

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

<!--Die Variable textList ist eine ArrayList<Formatierung>, die


im Servlet aus der Datenbank ausgelesen wird und alle
Formatierungen der ausgewaehlten WebSite enthaelt. Die
Formatierungsobjekte beinhalten jeweils eine ArrayList<Text>. -->
<c:forEach var="textList" items="${textList}">
<!--Die Variable text ist eine ArrayList<Text>, die den passenden
Text zur Formatierung enthaelt-->
<c:forEach var="text" items="${textList.text}">
<tr>
<td>Text</td>
<td>
<!--Die zu veraendernde Texte werden in einem Textfeld ausgelesen-->
<input type="text" name="<c:out value='${text.name}' />"
value="<c:out value='${text.name}' />">
</td>
<td>&nbsp</td>
</tr>
</c:forEach>
<tr>
<td>Formatierung</td>
<td>
<select name="FormatierungTextSelectOben<c:out value='${textList.name}' />" >
<!--Die passende Formatierung zum Text wird vorausgewaehlt. -->
<option selected value="<c:out value='${textList.name}' />">
<c:out value="${textList.name}" />
</option>
<!--Alle Formatierungen werden ausgelesen-->
<c:forEach var="formatierung" items="${formatierung}">
<option value="<c:out value='${formatierung.name}' />">
<c:out value="${formatierung.name}" />
</option>
</c:forEach>
</select>
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>

300

13.6 ndern von Objekten der Klasse WebSite

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

<td>&nbsp</td>
<td>&nbsp</td>
</tr>
</c:forEach>
<tr>
<td>Text</td>
<td>
<!--Hier kann ein neuer Text eingegeben werden.-->
<input type="text" name="TextName" value="">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>
Formatierung
</td>
<td>
<!--Alle Formatierungen werden ausgelesen-->
<select name="FormatierungTextSelect" >
<c:forEach var="formatierung" items="${formatierung}">
<option value="<c:out value='${formatierung.name}' />">
<c:out value="${formatierung.name}" />
</option>
</c:forEach>
</select>
</td>
<td>
&nbsp&nbsp&nbsp
<!--Hier wird ein neuer Text hinzugefuegt.-->
<input type="submit" name="Text"
value="Text hinzuf&uuml;gen" class="button" />
</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<!--Wenn Sie auf den Weiter-Button klicken, gelangen Sie zum
Formular aendernWebSiteBild.jsp.-->
<input type="submit" name="WeiterText" value="Weiter" class="button" />
</td>

301

13 Unser Content-Management-System

116
117
118
119
120
121
122

</tr>
</table>
</form>
</span>
</div>
</body>
</html>
Listing 13.25: aendernWebSiteText.jsp

13.6.3 ndern der Bilder


Im dritten Schritt knnen wir unsere Bildobjekte modizieren: Wir ersetzen die Daten durch
BildComputer  und Bilder/computer.jpg  .

Abbildung 13.14: Formular Bild-ndern


Folgendes JSP gehrt zu dem oben stehenden Bild:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>&Auml;ndern Bild</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>
<div class= "box2">
<span class="menu">
<%@include file="menueEingabeWebSite.jsp"%>

302

13.6 ndern von Objekten der Klasse WebSite

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

</span>
</div>
<div class= "box3">
<span class="font4">
<form name=""
action="<%=request.getContextPath()%>/aendernWebSite"
method="GET">
<table align="center" valign="middle">
<!--Die ArrayList<Bild> bildList wird ausgelesen und es besteht
jetzt die Moeglichkeit den Namen und den Pfad zu aendern.-->
<c:forEach var="bildList" items="${bildList}">
<tr>
<td>Bild</td>
<td>
<input type="text" name="<c:out value='${bildList.name}' />"
value="<c:out value='${bildList.name}' />">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>Pfad</td>
<td><input type="text" name="<c:out value='${bildList.pfad}' />"
value="<c:out value='${bildList.pfad}' />">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
</c:forEach>
<tr>
<td>Bild</td>
<td>
<!--Es kann ein neues Bild mit Namen und Pfad eingegeben werden.-->
<input type="text" name="BildName" value="">
</td>
</tr>
<tr>
<td>Pfad</td>
<td>
<input type="text" name="BildPfad" value="">
</td>
<td>&nbsp&nbsp&nbsp

303

13 Unser Content-Management-System

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

<!--Es kann ein Bild der ArrayList<Bild> hinzugefuegt werden.-->


<input type="submit" name="Bild"
value="Bild hinzuf&uuml;gen" class="button" />
</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<!--Sie gelangen mit folgendem Button im aendernWebSiteBildPdf.jsp-->
<input type="submit" name="WeiterBild" value="Weiter" class="button" />
</td>
</tr>
</table>
</form>
</span>
</div>
</body>
</html>

Listing 13.26: aendernWebSiteBild.jsp

13.6.4 ndern der PDFs


Im letzten Schritt knnen wir noch das PDF ndern: Wir ersetzen die Daten des Links fr das
PDF wie folgt: PDFComputer und Dokumente/computer.pdf.

Abbildung 13.15: Formular PDF-ndern

Unser letztes Formular lautet:

304

13.6 ndern von Objekten der Klasse WebSite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

<%@page language="java" %>


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<link rel="stylesheet" href="Styles/stil.css" type="text/css">
<title>PDF &Auml;ndern</title>
</head>
<body>
<div class="box1">
<img src="Bilder/oben.jpg" width="800" height="100">
</div>
<div class= "box2">
<span class="menu">
<%@include file="menueEingabeWebSite.jsp"%>
</span>
</div>
<div class= "box3">
<span class="font4">
<form name=""
action="<%=request.getContextPath()%>/aendernWebSite"
method="GET">
<table align="center" valign="middle">
<!--Die ArrayList<PDF> pdfList wird ausgelesen und es besteht
jetzt die Moeglichkeit den Namen und den Pfad zu aendern.-->
<c:forEach var="pdfList" items="${pdfList}">
<tr>
<td>Pdf</td>
<td><input type="text" name="<c:out value='${pdfList.name}' />"
value="<c:out value='${pdfList.name}' />">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>Pfad</td>
<td>
<input type="text" name="<c:out value='${pdfList.pfad}' />"
value="<c:out value='${pdfList.pfad}' />">
</td>
<td>&nbsp</td>
</tr>
<tr>
<td>&nbsp</td><td>&nbsp</td><td>&nbsp</td>
</tr>
</c:forEach>
<tr>

305

13 Unser Content-Management-System

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

<td>PDF</td>
<td><input type="text" name="PdfName" value=""></td>
<td>&nbsp</td>
</tr>
<tr>
<td>Pfad</td>
<td><input type="text" name="PdfPfad" value=""></td>
<td>&nbsp&nbsp&nbsp
<input type="submit" name="Pdf" value="Pdf hinzufuegen" class="button" />
</td>
</tr>
<tr>
<td>&nbsp</td>
<td>&nbsp</td>
<td>&nbsp</td>
</tr>
<tr>
<td colspan="3" align="center">
<input type="submit" name="Eingabe" value="Eingabe" class="button" />
</td>
</tr>
</table>
</form>
</span>
</div>
</body>
</html>
Listing 13.27: aendernWebSitePdf.jsp
Schauen wir uns das Ergebnis an, erhalten wir unten stehende Ausgabe:

Abbildung 13.16: Ausgabe der nderungen im Browser

306

13.6 ndern von Objekten der Klasse WebSite

13.6.5 Das ndern-Servlet


Fr das entsprechende Servlet erstellen wir als Erstes das Servlet-Mapping fr unser aendernWebSiteServlet.java in der web.xml:

1
2
3
4
5
6
7
8

<servlet>
<servlet-name>aendernWebSite</servlet-name>
<servlet-class>Servlets.aendernWebSiteServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>aendernWebSite</servlet-name>
<url-pattern>/aendernWebSite</url-pattern>
</servlet-mapping>
Listing 13.28: webAendern.xml

In unten stehendem Servlet ersetzen wir die Texte, Bilder und PDFs jeweils, indem wir die alte
ArrayList auslesen und gleichzeitig die Neue einlesen. Ich habe nicht jedes Element eins zu eins
ersetzt. Sollten Sie dies wollen, mssen Sie die ndern-Formulare anders gestalten.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

package Servlets;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

Datenbankabfragen.WebSiteDaten;
Datenbankentwurf.Bild;
Datenbankentwurf.Formatierung;
Datenbankentwurf.Link;
Datenbankentwurf.PDF;
Datenbankentwurf.Text;
Datenbankentwurf.WebSite;
java.io.IOException;
java.util.ArrayList;
java.util.Iterator;
java.util.List;
javax.servlet.http.HttpSession;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.ServletException;

public class aendernWebSiteServlet extends HttpServlet {


protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
ArrayList<Link> arrayListLink = new ArrayList<Link>();
ArrayList<Formatierung> textList = new ArrayList<Formatierung>();
ArrayList<Text> textAlt = new ArrayList<Text>();
ArrayList<Bild> bildList = new ArrayList<Bild>();

307

13 Unser Content-Management-System

ArrayList<PDF> pdfList = new ArrayList<PDF>();


ArrayList<Bild> bildListAlt = new ArrayList<Bild>();
ArrayList<PDF> pdfListAlt = new ArrayList<PDF>();
ArrayList<Link> linkList = new ArrayList<Link>();
String reihenfolge;
String ebene;
String unterEbene;
Link linkNeu;
Link linkAlt;

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

/*Wird im Formular aendernWebSiteLinkFolgende.jsp auf den


den Hyperlink Aendern Web geklickt, wird dieser if-Zweig ausgefuehrt:*/
if(request.getParameter("aWeb")!= null){
request.getRequestDispatcher("aendernWebSiteLink.jsp").
forward(request, response);
}
/*Wird im Formular aendernWebSiteLink.jsp auf den Button Aendern geklickt,
wird folgender Ausdruck wahr:*/
if(request.getParameter("Aendern")!= null){
/*Sollte es diese Session-Attribute bereits geben, werden sie
aus der Session gelscht.*/
request.getSession().removeAttribute("linkNeu");
request.getSession().removeAttribute("linkAlt");
request.getSession().removeAttribute("reihenfolge");
request.getSession().removeAttribute("ebene");
request.getSession().removeAttribute("textList");
request.getSession().removeAttribute("textAlt");
request.getSession().removeAttribute("bildList");
request.getSession().removeAttribute("pdfList");
request.getSession().removeAttribute("bildListAlt");
request.getSession().removeAttribute("pdfListAlt");
/*Der alte Link wird aus dem aendernWebSiteLink.jsp ausgelesen.*/
String linkAltName = request.getParameter("Link");
linkAlt = new Link(linkAltName);
/*Die Reihenfolge und die Ebene wird aus der Datenbank ausgelesen*/
WebSiteDaten wsd = new WebSiteDaten();
WebSite w = wsd.auslesenEinzeln(linkAltName, request);
reihenfolge = w.getReihenfolge();
ebene = w.getEbene();
/*Die Daten werden der Session als Attribute bergeben.*/
request.getSession().setAttribute("linkAltName", linkAltName);
request.getSession().setAttribute("reihenfolge", reihenfolge);
request.getSession().setAttribute("ebene", ebene);

308

13.6 ndern von Objekten der Klasse WebSite

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

/*Das Formular wird weitergesendet.*/


request.getRequestDispatcher("aendernWebSiteLinkFolgende.jsp").
forward(request, response);
}
/*Wurde im aendernWebSiteLinkFolgende.jsp auf den Link WeiterLink
geklickt, wird folgender Ausdruck wahr.*/
if(request.getParameter("WeiterLink")!= null){
/*Wir lesen den genderten Link aus dem Formular aus.*/
String li = request.getParameter("Link");
linkNeu = new Link(li);
/*Wir lesen den alten Linknamen aus der Session aus.*/
String linkAltName = (String)request.getSession().
getAttribute("linkAltName");
/*Der neue Link wird der Session bergeben.*/
request.getSession().setAttribute("linkNeu", linkNeu);
/*Wir lesen die genderte Reihenfolge und die neue Ebene aus dem
Request aus. */
String reihenfolgeNeu = request.getParameter("Reihenfolge");
String ebeneNeu = request.getParameter("Ebene");
request.getSession().setAttribute("reihenfolgeNeu", reihenfolgeNeu);
request.getSession().setAttribute("ebeneNeu", ebeneNeu);
/*Die Formatierungsobjekte mit den darin enthaltenen Texten
werden ausgelesen.*/
WebSiteDaten wsd = new WebSiteDaten();
textList = (ArrayList<Formatierung>)wsd.auslesenText(linkAltName, request);
/*Wir bergeben das Formatierungsobjekt, das eine ArrayList<Text>
enthlt, der Session als Attribute.*/
request.getSession().setAttribute("textList", textList);
/*Wir lesen den Text, die Bilder und die PDFs aus der
Datenbank aus.*/
WebSiteDaten w = new WebSiteDaten();
WebSite ws = w.auslesenEinzeln(linkAltName, request);
textAlt = ws.getText();
bildList = ws.getBild();
pdfList = ws.getPdf();
/*Wir bergeben der Session alle Attribute und erstellen
Listen sowohl fr die neuen als auch die alten Werte.*/
request.getSession().setAttribute("textAlt", textAlt);

309

13 Unser Content-Management-System

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176

310

request.getSession().setAttribute("bildList", bildList);
request.getSession().setAttribute("pdfList", pdfList);
request.getSession().setAttribute("bildListAlt", bildList);
request.getSession().setAttribute("pdfListAlt", pdfList);
/*Wir senden unsere Daten an das Formular aendernWebSiteText.jsp.*/
request.getRequestDispatcher("aendernWebSiteText.jsp").
forward(request, response);
}
/*Wurde im Formular auf den Button "Text hinzufgen" geklickt,
wird folgendes ausgefhrt:*/
if(request.getParameter("Text")!=null){
/*Wir lesen den Namen des Textes aus dem Formular aus und erstellen
ein Textobjekt.*/
Text t = new Text(request.getParameter("TextName"));
/*Wir fgen diese Textobejekt einer ArrayList<Text> hinzu,*/
ArrayList<Text> ate = new ArrayList<Text>();
ate.add(t);
/*und diese List ArrayList<Text> bergeben wir einem Formatierungsobjekt.*/
Formatierung f = new Formatierung(request.
getParameter("FormatierungTextSelect"),ate);
/*Wir lesen die "alten" Formatierungen, die die Textobjekte enthalten, aus
der Session aus.*/
textList = (ArrayList<Formatierung>)request.getSession().
getAttribute("textList");
/*Wir erstellen eine neue ArrayList fr unsere Formatierungen und fgen
dieser weiter unten die neuen bzw. genderten Texte hinzu.*/
ArrayList<Formatierung> textListNeu = new ArrayList<Formatierung>();
Formatierung form = null;
/*Wir lesen alle Formatierungen aus der textList aus,*/
for(Formatierung fo: textList){
/*und anschlieend die darin enthaltene Texte, die sich in der
ArrayList<Text> befinden*/
ArrayList<Text> al = fo.getText();
ArrayList<Text> at = new ArrayList<Text>();
Text texte = null;
/*und hier werden die einzelnen Texte ausgelesen*/

13.6 ndern von Objekten der Klasse WebSite

177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225

for(Text text: al){


/*Wir erstellen ein neues Formatierungsobjekt mit Textobjekten
aus den Parametern, die wir aus dem Formular und der
for-Schleifen auslesen, und*/
texte = new Text(request.getParameter(text.getName()));
at.add(texte);
form = new Formatierung(request.getParameter
("FormatierungTextSelectOben"+fo.getName()), at);
/*wir fgen diese einer neuer textListNeu hinzu.*/
textListNeu.add(form);
}
}
/*Wir bergeben oben erstelltes Formatierungsobjekt f auch der
textListNeu.*/
textListNeu.add(f);
/*Wir lschen die alte textList und ersetzen sie durch eine neue
textListNeu.*/
request.getSession().removeAttribute("textList");
request.getSession().setAttribute("textList", textListNeu);
/*Wir schicken die Daten an das aendernWebSiteText.jsp zurck.*/
request.getRequestDispatcher("aendernWebSiteText.jsp").
forward(request, response);
}
/*Wird im Formular aendernWebSiteText.jsp auf den Button
WeiterText geklickt, wird folgender if-Zweig ausgefhrt:*/
if(request.getParameter("WeiterText")!= null){
/*Steht in dem Feld TextName etwas, wird folgender Ausdruck wahr.*/
if (request.getParameter("TextName")!= null
&& request.getParameter("TextName").length()>0){
/*Der Name des Textes wird aus dem Formular ausgelesen,*/
Text t = new Text(request.getParameter("TextName"));
/*und der ArrayList<Text> hinzugefgt,*/
ArrayList<Text> ate = new ArrayList<Text>();
ate.add(t);
/*und diese wiederum wird dem Formatierungsobjekt hinzugefgt.*/
Formatierung f = new Formatierung(request.getParameter
("FormatierungTextSelect"),ate);

311

13 Unser Content-Management-System

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

312

ArrayList<Formatierung> textListNeu = new ArrayList<Formatierung>();


/*Die bereits erstellte Liste textList wird aus der Session ausgelesen,*/
textList = (ArrayList<Formatierung>)request.getSession().
getAttribute("textList");
/*Es werden die Werte des Formulars, die den Namen der alten ArrayList
textList haben, durch die Werte, die neu in das Formular eingegeben
wurden, ersetzt.*/
for(Formatierung fo: textList){
ArrayList<Text> al = fo.getText();
for(Text tex: al){
Text text = new Text(request.getParameter(tex.getName()));
ArrayList<Text> at = new ArrayList<Text>();
at.add(text);
Formatierung form = new Formatierung(request.getParameter
("FormatierungTextSelectOben"+fo.getName()), at);
textListNeu.add(form);
}
}
/*und das Formatierungsobjekt wird dieser textListNeu hinzugefgt.*/
textListNeu.add(f);
/*Wir lschen die alte textList und ersetzen sie durch eine neue
textListNeu.*/
request.getSession().removeAttribute("textList");
request.getSession().setAttribute("textList", textListNeu);
request.getRequestDispatcher("aendernWebSiteBild.jsp").forward(request, response);
/*Steht in dem Feld TextName nichts, wird folgender Ausdruck wahr.*/
} else{
/*So werden nur die Textfelder, in denen etwas steht, der
Formatierungsliste hinzugefgt:*/
textList = (ArrayList<Formatierung>)request.getSession().
getAttribute("textList");
ArrayList<Formatierung> textListNeu = new ArrayList<Formatierung>();
/*Es werden die Werte des Formular, die den Namen der alten ArrayList
textList haben, durch die Werte, die neu in das Formular eingegeben
wurden, ersetzt.*/
for(Formatierung fo: textList){
ArrayList<Text> al = fo.getText();
for(Text tex: al){
Text text = new Text(request.getParameter(tex.getName()));
ArrayList<Text> at = new ArrayList<Text>();

13.6 ndern von Objekten der Klasse WebSite

275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323

at.add(text);
Formatierung form = new Formatierung(request.getParameter
("FormatierungTextSelectOben"+fo.getName()), at);
textListNeu.add(form);
}
}
/*Wir lschen die alte textList und ersetzen sie durch eine neue
textListNeu.*/
request.getSession().removeAttribute("textList");
request.getSession().setAttribute("textList", textListNeu);
request.getRequestDispatcher("aendernWebSiteBild.jsp").
forward(request, response);
}
}
/*Wird im aendernWebSiteBild.jsp auf den Button "Bild hinzufgen" geklickt,
wird Folgendes ausgefhrt:*/
if(request.getParameter("Bild")!=null){
/*Es wird ein neues Bild mit den Daten aus dem Formular instanziiert.*/
Bild bild = new Bild
(request.getParameter("BildName"), request.getParameter("BildPfad"));
/*Die alte bildList, die Bilder der zu ndernden WebSite enthlt, wird
durch eine bildList mit den genderten Bildern ersetzt.*/
bildList = (ArrayList<Bild>)request.getSession().getAttribute("bildList");
ArrayList<Bild> bildListNeu = new ArrayList<Bild>();
for(Bild b :bildList){
Bild bi = new Bild
(request.getParameter(b.getName()), request.getParameter(b.getPfad()));
bildListNeu.add(bi);
}
bildListNeu.add(bild);
request.getSession().removeAttribute("bildList");
request.getSession().setAttribute("bildList", bildListNeu);
request.getRequestDispatcher("aendernWebSiteBild.jsp").
forward(request, response);
}
/*Wird im Formular aendernWebSiteBild.jsp auf den Button Weiter geklickt,
wird folgendes ausgefhrt:*/
if(request.getParameter("WeiterBild")!= null){
/*Steht in den Feldern Bildname und Bildpfad etwas, soll eine neues
Bildobjekt der bildList hinzugefgt werden.*/
if (request.getParameter("BildName")!= null
&& request.getParameter("BildName").length()>0 ||
request.getParameter("BildPfad")!= null

313

13 Unser Content-Management-System

324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372

314

&& request.getParameter("BildPfad").length()>0){
Bild bild = new Bild
(request.getParameter("BildName"), request.getParameter("BildPfad"));
bildList = (ArrayList<Bild>)request.getSession().
getAttribute("bildList");
ArrayList<Bild> bildListNeu = new ArrayList<Bild>();
/*Die alten Werte der bildList sollen durch die Neuen ersetzt werden,
falls der Benutzer nochmals Vernderungen vorgenommen hat.*/
for(Bild b :bildList){
Bild bi = new Bild
(request.getParameter(b.getName()), request.getParameter(b.getPfad()));
bildListNeu.add(bi);
}
bildListNeu.add(bild);
request.getSession().removeAttribute("bildList");
request.getSession().setAttribute("bildList", bildListNeu);
request.getRequestDispatcher("aendernWebSitePdf.jsp").
forward(request, response);
/*Steht in den Feldern Bildname und Bildpfad nichts, */
} else{
bildList = (ArrayList<Bild>)request.getSession().
getAttribute("bildList");
ArrayList<Bild> bildListNeu = new ArrayList<Bild>();
/*sollen nur die alten Werte der bildList durch die neuen Werte
ersetzt werden.*/
for(Bild b :bildList){
Bild bi = new Bild
(request.getParameter(b.getName()), request.getParameter(b.getPfad()));
bildListNeu.add(bi);
}
request.getSession().removeAttribute("bildList");
request.getSession().setAttribute("bildList", bildListNeu);
request.getRequestDispatcher("aendernWebSitePdf.jsp").
forward(request, response);
}
}
/*Fr die Eingabe der PDF's gilt analog zu der Eingabe von Bildern
das gleiche:*/
if(request.getParameter("Pdf")!=null){
PDF neuesPdf = new PDF
(request.getParameter("PdfName"), request.getParameter("PdfPfad"));
pdfList = (ArrayList<PDF>)request.getSession().getAttribute("pdfList");

13.6 ndern von Objekten der Klasse WebSite

373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421

ArrayList pdfListNeu = new ArrayList();


for(PDF p: pdfList){
PDF pdf = new PDF
(request.getParameter(p.getName()), request.getParameter(p.getPfad()));
pdfListNeu.add(pdf);
}
pdfListNeu.add(neuesPdf);
request.getSession().removeAttribute("pdfList");
request.getSession().setAttribute("pdfList", pdfListNeu);
request.getRequestDispatcher("aendernWebSitePdf.jsp").
forward(request, response);
}
/*Wird im aendernWebSitePdf.jsp auf den Eingabe-Button geklickt,
werden alle Daten gespeichert.*/
if(request.getParameter("Eingabe") != null){
/*Sind die Felder PdfName und PdfPfad nicht leer, wird folgender
if-Zweig abgearbeitet: */
if (request.getParameter("PdfName")!= null
&& request.getParameter("PdfName").length()>0
||request.getParameter("PdfPfad")!= null
&& request.getParameter("PdfPfad").length()>0){
PDF neuesPdf = new PDF
(request.getParameter("PdfName"), request.getParameter("PdfPfad"));
pdfList = (ArrayList<PDF>)request.getSession().getAttribute("pdfList");
ArrayList<PDF> pdfListNeu = new ArrayList<PDF>();
for(PDF p: pdfList){
PDF pdf = new PDF
(request.getParameter(p.getName()), request.getParameter(p.getPfad()));
pdfListNeu.add(pdf);
}
pdfListNeu.add(neuesPdf);
request.getSession().removeAttribute("pdfList");
request.getSession().setAttribute("pdfList", pdfListNeu);
/*Es wird ein neues Objekt der Klasse WebSiteDaten, die alle Abfragen
enthlt, instanziiert.*/
WebSiteDaten webDa = new WebSiteDaten();
//Die alten und neuen Werte werden aus der Session ausgelesen,
linkNeu = (Link)request.getSession().getAttribute("linkNeu");
String linkAltName = (String)request.getSession().
getAttribute("linkAltName");
linkAlt = new Link(linkAltName);
textList = (ArrayList<Formatierung>)request.getSession().
getAttribute("textList");

315

13 Unser Content-Management-System

422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470

316

bildList = (ArrayList<Bild>)request.getSession().getAttribute("bildList");
reihenfolge = (String)request.getSession().getAttribute("reihenfolgeNeu");
pdfList = (ArrayList<PDF>)request.getSession().getAttribute("pdfList");
ebene = (String)request.getSession().getAttribute("ebeneNeu");
textAlt = (ArrayList<Text>)request.getSession().getAttribute("textAlt");
bildListAlt = (ArrayList<Bild>)request.getSession().getAttribute("bildListAlt");
pdfListAlt = (ArrayList<PDF>)request.getSession().getAttribute("pdfListAlt");
/*Die neuen und alten Werte werden der Methode bergeben, die die
Werte der WebSite ndert.*/
webDa.updateWebSite(linkAlt, linkNeu, textList, textAlt, bildList, bildListAlt,
pdfList, pdfListAlt, reihenfolge, ebene, request);
request.getRequestDispatcher("aendernWebSiteLink.jsp").
forward(request, response);
/*Sind die Felder PdfName und PdfPfad leer, wird folgender
else-Zweig abgearbeitet: */
} else{
pdfList = (ArrayList<PDF>)request.getSession().getAttribute("pdfList");
ArrayList<PDF> pdfListNeu = new ArrayList<PDF>();
for(PDF p: pdfList){
PDF pdf = new PDF
(request.getParameter(p.getName()), request.getParameter(p.getPfad()));
pdfListNeu.add(pdf);
}
request.getSession().removeAttribute("pdfList");
request.getSession().setAttribute("pdfList", pdfListNeu);
/*Die Werte werden aus der Session ausgelesen und der Methode
updateWebSite() der Klasse WebSiteDaten bergeben:*/
WebSiteDaten webDa = new WebSiteDaten();
linkNeu = (Link)request.getSession().getAttribute("linkNeu");
String linkAltName = (String)request.getSession().
getAttribute("linkAltName");
linkAlt = new Link(linkAltName);
textList = (ArrayList<Formatierung>)request.getSession().
getAttribute("textList");
for(Formatierung formatierung: textList){
System.out.println("Name der Formatierung ganz unten: "
+formatierung.getName());
}
bildList = (ArrayList<Bild>)request.getSession().getAttribute("bildList");
reihenfolge = (String)request.getSession().getAttribute("reihenfolgeNeu");
pdfList = (ArrayList<PDF>)request.getSession().getAttribute("pdfList");
ebene = (String)request.getSession().getAttribute("ebeneNeu");
textAlt = (ArrayList<Text>)request.getSession().getAttribute("textAlt");

13.6 ndern von Objekten der Klasse WebSite

471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488

bildListAlt = (ArrayList<Bild>)request.getSession().getAttribute("bildListAlt");
pdfListAlt = (ArrayList<PDF>)request.getSession().getAttribute("pdfListAlt");
webDa.updateWebSite(linkAlt, linkNeu, textList, textAlt, bildList, bildListAlt,
pdfList, pdfListAlt, reihenfolge, ebene, request);
request.getRequestDispatcher("aendernWebSiteLink.jsp").
forward(request, response);
}
}
}

protected void doPost(HttpServletRequest request,


HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

Listing 13.29: aendernWebSiteServlet.java

317

14 Anhang

14.1 Literaturverzeichnis
Edlich, Stefan; Hrning, Henrik; Hrning, Reidar; Paterson, Jim: The denite Guide to db4o,
Apress, 2006.
Rmer, Patrick; Visengeriyeva, Larysa: db4o, Software & Support Verlag GmbH, 2007.

14.2 Weitere Informationsquellen

www.db4o.de
Deutschsprachige Seite der db4objects, Inc. Hier nden Sie alle Informationen rund um das Thema db4o, einschlielich hilfreicher Links zu weitergehenden Informationen.

db4o-Tutorial
Dieses Tutorial wird mit der Datenbank db4o heruntergeladen und bendet sich im Verzeichnis
doc/tutorial.

db4o-HTML-Referenz
Diese Referenz ist ebenfalls Teil des db4o-Paketes und Sie nden es im Ordner doc/reference.

http://www.netbeans-forum.de/
Sollten Sie Fragen rund um das Thema NetBeans haben, knnen Sie Ihre Fragen in dieses Forum
stellen.

http://odbms.org/
Englischsprachiges Portal rund um das Thema Objektorientierte Datenbanken, das Unterrichtsund Forschungszwecken dient. Die Seite enthlt eine groe Sammlung an Artikeln und Links zum
Thema.

http://www.polepos.org/
Englischsprachige Seite, die Teil des Sourceforge.net-Projektes ist, die Datenbanken, wie z. B.
MySQL und db4o, nach verschiedenen Kriterien miteinander in Beziehung setzt.

http://de.wikipedia.org/wiki/Db4o
Deutschsprachiger schnellwachsender Eintrag fr db4o bei Wikipedia.org.

319

Index

.NET, 1

Bedingungen, einfache, 94, 112

.yap, 16

Bedingungen, mit Vergleichen, 117

<c:choose>, 205

Bedingungen, zusammengesetzte, 94, 99, 114

<c:forEach>, 198

Beispielobjekt, 55

<c:if>, 203

Beziehungen, 31

<c:otherwise>, 205
<c:set>, 202

Cache, 139, 221

<c:when>, 205

cascadeOnDelete(), 41

<context-param>, 211

cascadeOnUpdate(), 45, 130, 227

<dispatcher>, 208

Casten, 18

<init-param>, 211

Client, 174, 219

<servlet>, 211

Client-Server-Modus, 219

1:1-Beziehung, 31, 33

close(), 15, 151

1:n-Beziehung, 31, 33, 55

Collections, 109
commit(), 151

a:hover, 183

Comparator, 106

Abfrage, komplexe, 103

compare(), 106

Abfragekonzepte, 87

Consistency, 158

Abstrakte Klassen, 47, 55

constrain(), 111, 112, 114

ACID, 158

Constraint, 111, 117

activationDepth(), 127

contains(), 117

add(), 58

Content-Management-System, 235

Aktivierungstiefe, 127

contentType, 192

aktualisieren, 227

Context, 178

and(), 114

Context path, 181

Anfrage, 174

Context-Listener, 218

anonyme Klasse, 95, 99

Context-Parameter, 211, 219

Antwort, 174

context.xml, 181

Antwortzeiten, 31, 164

contextDestroyed(), 216

Applikation, 178

contextInitialized(), 216

Arbeitsspeicher, 139, 219, 227

Controller, 167

ArrayList, 17, 58, 124, 130, 198

CREATE-TABLE-Befehl, 13

Atomicity, 158

CSS, 182

attributeAdded(), 218

CSS-Format, 11

attributeRemoved(), 218

CSS-Formatierung, 239

attributeReplaced(), 218

Custom Tags, 192, 197

Bedingungen, 87

DataBaseFileLockedException, 140

321

Index

Datenbankabfragen, 167

getAttribute(), 177, 178

Datenbanken teilen, 165

getContextPath(), 170, 176

Datenbankentwurf, 167

getID(java.lang.Object obj), 15

Datenredundanz, 31, 33

getInitParameter(), 211

db4o Collections, 58

getMessageSender(), 147

Db4oServletContextListener, 219

getName(), 200

Db4oSessionListener, 221

getParameter(), 176, 178

Default-Fall, 205

getRequestDispatcher(), 176, 177

Default-Wert, 17

getServletCong(), 211

Deklaration, 191, 194

getServletContext(), 178

delete(), 15, 21

getSession(), 177

Denormalisieren, 165

Getter- und Setter-Methoden, 11

Denormalisierung, 31

getWriter(), 175

Deployment, 181

GPL, 3

Deployment Descriptor, 211

grantAccess(), 140

descend(), 112

greater(), 117

destroy(), 206
Direktive, 191

has-a-Beziehung, 33, 127

div-Tag, 182

HashMap, 198

doFilter(), 206

hasNext(), 15

doGet(), 168

Hibernate, 1, 4, 28

doPost(), 168

HTTP-Protokoll, 174

double, 17

HttpRequestAttributeListener, 218

Durability, 158

HttpServlet, 168
HttpServletRequest, 176, 178, 222

Embedded-Modus, 139, 144, 158, 219, 235

HttpServletResponse, 175, 177

endsWith(), 117

HttpSessionActivationListener, 218

Entity-Relationship-Modell, 31

HttpSessionAttributeListener, 214

ErrorPage, 208

HttpSessionBindingEvent, 214, 218

execute(), 112

HttpSessionBindingListener, 218

Expression, 191, 192

HttpSessionEvent, 216, 218

ext(), 15

HttpSessionListener, 216, 219, 221

ExtObjectContainer, 15, 158, 226


identity(), 117
Filter, 167, 206

IllegalStateException, 119

Filter-Mapping, 208

import, 192

FilterChain, 208

Include, 192, 208

nal, 99

init(), 206

oat, 17

INSERT-Befehl, 17

Formatierung, 239

Installation von db4o, 7

FORWARD, 208

Instanzen, 11

forward(), 176

Instanzvariable, 136, 194

Fremdschlssel, 31

int, 17
Interface, 47, 55

Geltungsbereich, 202

Interface Comparator, 106

Generics, 18

Interface Constraint, 87, 111

generisch, 18

Interface HttpServletRequest, 176, 178

GET, 168, 174

Interface HttpServletResponse, 177

get(), 14, 17, 55

Interface Query, 87, 111

322

Index

Interfaces Constraint, 117

native Methoden, 87

InterruptedException, 140

Native Queries, 87, 124

invalidate(), 177

NetBeans, 2, 5, 167, 169

is-a-Beziehung, 47, 51

Netzwerkmodus, 139

Isolation, 158

next(), 15

Isolationsstufen, 159

Normalisieren, 165

Iterator, 25

Normalisierung, 31
not(), 111, 114

Java Server Faces, 6


JSP, 167, 168, 182

notify(), 145
NullPointerException, 128, 158

JSTL, 197
jstl.jar, 197
Kapselung, 11
key, 200
Klasse, 11
Klasse Collections, 109
Klasse LockManager, 162
Klasse Predicate, 87, 94, 99, 103, 106
Klasse Thread, 134
Klassenvariable, 136, 194
Konstruktoraufruf, 49
Konstruktoren, 11
Kontrollstruktur, 203, 205
like(), 117
LinkedList, 130
Listener, 214
Lizenz, 3
localhost, 141
LOCK, 136
locken, 160, 162
LockManager, 162

ObjectContainer, 14, 221, 222


ObjectSet, 15, 17
Objekte, 11
objektorientierter Datenbankentwurf, 29
OID, 14, 15, 33, 162
openClient(), 141, 144, 221
openFile(), 15, 151
openServer(), 140, 144
orderAscending(), 111, 121
orderDescending(), 111
Out-of-Band-Signalling, 139, 145
Package com.db4o, 14
Package com.db4o.ext, 15, 158, 226
Package com.db4o.messaging, 145
Package com.db4o.query, 87, 111
Package com.db4o.query.Predicate, 94
Package java.io, 175
Package java.lang, 133
Package java.util, 109
Page, 192
Page-Attribut, 192
pageEncoding, 192
Performance, 4

m:n-Beziehung, 31, 33, 83

PolePosition, 4

match(), 94, 95, 99, 103

Portnummer, 141

MessageRecipient, 145

POST, 168, 174

MessageSender, 145

Predicate, 87, 94, 99, 103, 106

META-INF, 181

Primrschlssel, 13, 31

Methode ext(), 15

PRIMARY KEY, 13

Microsoft .NET, 1

primitiven Datentyp, 17

Mime-Type, 192

print(), 192

Model, 167

println(), 175

Model-View-Controller, 1, 167

PrintWriter, 209

Mono, 1

PrintWriter-Objekt, 175

Multithreading, 133

processMessage(), 145

MVC, 167
MySQL, 4

Query, 111

323

Index

query(), 95, 106

sessionDidActivate(), 218

Query-by-Example, 17, 55, 87, 124

sessionWillPassivate(), 218
set(), 14, 16, 49

Read Committed, 159

setAttribute(), 177, 178

Read Uncommitted, 159

setMessageRecipient(), 145

referentielle Integritt, 32, 43, 77

setPriority(), 133

refresh(), 158, 221, 226, 235

setSemaphore(), 160

relationales Mapping, 28

Simple Object Database Access, 111

releaseSemaphore(), 160

Skriptlet, 191, 194

remove(), 58

smaller(), 117

removeAttribute(), 178

Solo-Modus, 139

Repeatable Read, 159

Sortieren, 106, 121

Request, 174, 178, 206

span-Tag, 182

Request Message Body, 174

SQL-Befehle, 87

Request-Listener, 218

Standard Tag Library, 197

requestDestroyed(), 218

standard.jar, 197

RequestDispatcher, 208

Standardaktivierungstiefe, 128

requestInitialized(), 218

Standardkonstruktor, 11, 49

Response, 174, 206

Standardwert, 17

reverse(), 109

start(), 134

Rollback, 88, 151, 158, 235

startsWith(), 117

rollback(), 151

stil.css, 182

Rollover-Eekt, 183

StopServer-Objekt, 147

run(), 133

Struts, 6

Runnable Interface, 133

Subklasse, 47
super(), 49

S.O.D.A., 87, 111, 124

Superklasse, 47

scope, 178, 202

Synchronisation, 135

SELECT, 21

synchronisierte Blcke, 135, 159, 160

Semaphore, 138, 159, 160, 235

Syntaxelemente, JSP, 191

send(), 147
sendRedirect(), 177

Taglib, 192

Serializable, 159

Taglib-Direktive, 192

Server, 174, 219

TCP/IP-Port, 140

Servlet, 167, 168, 175

TCP/IP-Protokoll, 139

Servlet-Mapping, 169

teilen, Datenbanken, 165

Servlet-Parameter, 211

this, 145

ServletContextAttributeEvent, 218

Thread, 134, 140, 174

ServletContextAttributeListener, 218

Thread.MAX_PRIORITY, 133

ServletContextEvent, 216

Thread.MIN_PRIORITY, 133

ServletContextListener, 216, 219

Thread.NORM_PRIORITY, 133

ServletRequestAttributeEvent, 218

Threads, 133

ServletRequestEvent, 218

threadsafe, 135

ServletRequestListener, 218

threadsicher, 135

Session, 177, 178

Tiefe Objektgraphen, 127

Session-Cong, 177

Timeout, 177

Session-Listener, 218

Tomcat, 144, 169, 181

sessionCreated(), 216

Transaktion, 103

sessionDestroyed(), 216

Transaktionen, 88, 151

324

Index

Transparente Aktivierung, 131


try-catch-nally-Block, 16
Unique Object Identier, 14, 33, 162
Update-Tiefe, 130, 227
updateDepth(), 130, 227
UTF-8, 192
value, 200
valueBound(), 218
valueUnbound(), 218
Vererbungsbeziehungen, 47
View, 167
wait(), 140
WAR-Datei, 181
Web Deployment Descriptor, 169
WEB-INF, 167
web.xml, 167, 169, 208, 211
webapp, 167
Webcontainer, 169
www.polepos.org, 4
www.sourceforge.net, 4
Zugri, 221
Zugrisgeschwindigkeit, 165

325