FACHHOCHSCHULE KÖLN, UNIVERSITY OF APPLIED SCIENES COLOGNE ABTEILUNG GUMMERSBACH FACHBEREICH INFORMATIK Diplomarbeit GEOGRAFISCHE INFORMATIONSSYSTEME UNTER BERÜCKSICHTIGUNG DER ORACLE SPATIAL TECHNIK von Reinhard S. Zöllner Neusser Landstr. 379 50769 Köln zur Erlangung des akademischen Grades Diplom - Informatiker (FH) 1. Prüfer: Frau Professor Dr. Heide Faeskorn-Woyke 2. Prüfer: Herr Professor Dr.-Ing. Jackson Roehrig Inhaltsverzeichnis Inhaltsverzeichnis i Abbildungsverzeichnis iii Tabellenverzeichnis v Abkürzungsverzeichnis vi Das Projekt Wassermanagement in Chile 1 Geografische Informationssysteme 3 2.1 Entstehung der GIS-Systeme 3 2.2 Die Elemente eines GIS-Systems 5 2.3 Darstellung von Daten 8 2.3.1 Vektordaten und Rasterdaten 8 2.3.2 Maßstäbe 11 2.4 Datenspeicherung und Verarbeitung 13 Datenbanksysteme 19 3.1 Datenbanksysteme 19 3.2 Oracle vs. MySQL 22 3.3 Ein Datenmodell 23 3.4 Die Oracle Spatial Technologie 32 3.5 Der Objekttype GEOMETRY 33 3.6 Indexing 40 3.7 Weitere Aspekte der Spatial Technologie 42 3.8 Was bewirkt die Spatial Technologie 42 Technologien mittels Java auf Datenbanken zuzugreifen 44 4.1 Systemarchitekturen 44 4.2 Prinzipieller Ablauf einer Datenbankabfrage mittels JDBC 46 4.3 Typen von JDBC – Treibern 49 4.4 Datenbankzugriffe unter Nutzung von Swing 51 4.6 Weitere Entwicklung des Tools 53 4.7 Java Server Pages 54 ArcInfo und ArcSDE 57 5.1 ArcInfo 57 5.2 ArcSDE 59 ANHANG 61 A 1 Literaturverzeichnis 62 A 2 Internetseiten 64 A 3 Verwendete Software 65 B SoftwareInstallationen 66 C DatenbankSkript 67 C 1 SQL - Skript Flussmodell 67 C 2 SQL - Skript kleines Flussmodell 100 C 3 SQL - Skript Daten für kleines Flussmodell 102 D Programmcode 103 D 1 dbt_Starter.java 103 D 2 anmeldung.java 107 D 3 oraZugriffsDaten.java 110 D 4 hauptmenu.java 112 D 5 changeData.java 117 D 6 druck.java 119 D 7 editData.java 121 D 8 eta.java 127 D 9 fpfu.java 129 D 10 fpofu.java 131 D 11 lookData.java 133 D 12 taa.java 138 E Pflichtenheft 143 Notizen 146 Erklärung 147 ii Abbildungsverzeichnis Nummer Seite 2.1 Zeitleiste 4 2.2 Aufbau von MVC bzw. GIS-Systemn 6 2.3 Dimensionen von Geometriedaten 7 2.4 Darstellung eines Objektes in Vektor- und Rasterdarstellung 9 2.5 Geometriedaten und deren graphische Ausgestaltung 11 2.6 Maßstäbe 13 2.7 Brunnenkarte 14 2.8 Brunnenkarte mit Raster 14 2.9 Quadtree-Prinzip 15 2.10 Verbindungskarte 16 2.11 Straßennetz mit Raster 17 3.1 Entität Fluss 24 3.2 Modellierung Gewässer – Fluss 24 3.3 Modellierung Fluss – Messpunkt 25 3.4 Messpunkt – Messwert 26 3.5 Verschiedene Messwerte 27 3.6 Erweitertes Datenmodell um den Messwert Nitrit 28 3.7 Fluss – Region 29 3.8 Spezifikation der Region 29 3.9 Modellierung Verwaltungsbehörde 30 3.10 Gesamtes Datenmodell 31 3.11 Kleines Datenmodell 32 3.12 Einfache geometrische Datentypen 33 iii 3.13 Rechteck 36 3.14 Polygon mit rechteckiger Öffnung 38 3.15 Rechteckprofil 39 3.16 Rasterung 40 3.17 hybrid indexing 41 4.1 2-Schichten-Architektur 45 4.2 3-Schichten-Architektur 45 4.3 Ablauf JDBC Anbindung 49 4.4 JDBC – Treibertypen und Kommunikation Anwendung – DB 51 4.5 Programmstruktur 53 5.1 ArcGIS 57 5.2 ArcCatalog 58 5.3 ArcMap 58 5.4 ArcToolbox 59 5.5 ArcSDE 59 5.6 Datenbankconnect 60 iv Tabellenverzeichnis Nummer 3.1 Seite SDO_GTYPE Werte 35 v Abkürzungsverzeichnis API Application Programming Interface EJB Enterprise Java Beans GIS Geografische Informationssysteme HTML Hyper Text Markup Language JDBC Java Database Connectivity JMS Java Message Service JNDI Java Naming and Directory Interface JSP Java Server Pages JTA Java Transaction API J2EE Java 2 Enterprise Edition ODBC Open Database Connectivity OGC Open GIS Consortium RMI Remote Method Invocation SQL Structured Query Language vi Kapitel 1 Das Projekt Wassermanagement in Chile Das Projekt, das hier kurz mit “Wassermanagement in Chile“ überschreiben ist, hat sich zum Ziel gesetzt, ein Monitoring- und Informationssystem für ein effizientes Wassermanagement in Flusseinzugsgebieten zu entwickeln. Dies soll dann erstmalig am Beispiel des Rio Aconcagua in Chile eingesetzt werden. Die Projektleitung liegt in Händen von Herrn Professor Dr.-Ing. J. Roehrig vom Institut für Tropentechnologie der Fachhochschule Köln. Für dieses Projekt konnten bereits im Vorfeld viele Partner gewonnen werden, die hier kurz aufgeführt werden : ?? Prof. Faeskorn-Woyke, Fachbereich Informatik, FH Köln ?? Prof. Sturm, Fachbereich Ver- und Entsorgungstechnik, FH Köln ?? Prof. Menz, Universität Bonn, Zentrum für Fernerkundung der Landoberfläche ?? Dr. Ole Larsen, Firma Hydrowelten ?? Dipl. Ing. Schneider , Firma UIT ?? Dr.-Ing. G. Kolisch , Wupperverband ?? Prof. Carlos Espinoza, Universidad de Chile ?? Prof. Eduardo Salgado, Universidad Católica de Valparaiso ?? Monica Pardo, Direccion General de Agua, Santiago de Chile ?? Christian Neumann, Direccion General de Agua, V Region ?? Ing. Marco Montt, Confederación del Rio Aconcagua. Die genaue Problemstellung kann in der Projektbeschreibung von Prof. Dr.-Ing. J. Roehrig nachgelesen werden. Hier wird sich aus der Sicht der Informatik der Problemstellung genähert. Dies bedeutet im einzelnen, dass erst einmal die Grundlagen von GIS-Systemen vorgestellt werden, da dies ein Gebiet ist, dass im Informatikstudium normalerweise nicht behandelt wird. -1- Danach wird in einem Kapitel über Datenbanksysteme eine kurze Betrachtung verschiedener Datenbanksysteme folgen. In diesem Kapitel wird auch ein Datenmodell erarbeitet, das für das Projekt eingesetzt werden kann. Des weiteren wird ein Auszug aus diesem Datenmodell umgesetzt, so dass dieses dann beispielhaft angewendet werden kann. Das Kapitel schließt mit Grundlagen zur Oracle Spatial Technologie ab, wobei hier der Bogen von den Grundlagen der GIS-Systeme zur Oracle Spatial Technologie geschlagen wird. Im vierten Kapitel wird gezeigt, wie mit Java auf Datenbanken zugegriffen werden kann. Das Datenmodell aus Kapitel 3 wird mit einer Standard – Java Benutzeroberfläche versehen. Im fünften Kapitel wird dann das GIS-System ArcInfo kurz betrachtet und gezeigt wie es möglich ist, mittels ArcSDE auf einer Oracle Datenbank verschiedene Aktionen auszuführen. Weitere Informationen zur Installation sind im Anhang zu finden. -2- Kapitel 2 Geografische Informationssysteme Geografische Informationssysteme, kurz als GIS-Systeme bezeichnet, werden heute in vielen verschiedenen Zusammenhängen und mit den verschiedensten anderen Technologien eingesetzt. Allen zugrunde liegt aber, dass die Daten in digitaler Form gespeichert werden. Erste Verwendung fanden GIS-Systeme bei Landkarten auf CD. Durch die weite Verbreitung des Internet und die dadurch bedingten neuen Anwendungen wurden hier auch GIS-Systeme eingesetzt. Dabei sind z.B. Stadtpläne zu nennen, aber auch bei der Erstellung von Wetterinformationen für verschiedenste Nutzer werden heutzutage GIS-Systeme eingesetzt. Auch Bauplanungen von größerem Ausmaß, wie z.B. Strassen und Landschaftsbau, sind die klassischen Einsatzgebiete von GIS-Systemen. Durch die Entwicklung von Navigationssystemen für Autos haben selbst in diesem Bereich GIS-Systeme neue Einsatzbereiche gefunden. In diesem Kapitel wird kurz auf die Entwicklung von GIS-Systemen eingegangen, um danach einen Blick auf die verwendeten Datenstrukturen und die verwendeten Algorithmen ( eine Grundlage für den Einsatz von GIS-Systemen ) zu legen. 2.1 Entstehung der GIS-Systeme Karten, Pläne und Informationen über seine nähere und weitere Umgebung war und ist für den Menschen von großer Bedeutung. Am Anfang um Wege zu bestimmten Orten zu finden, später um sich auf Kontinenten zurecht zu finden. Heute werden auch wieder die Informationen im kleinen benötigt, wie z.B. wem gehört ein Grundstück, welche Leitungen für Gas, Wasser und Strom sind wo verlegt ? Aber auch Informationen über Städte, Strassen, Flüsse und Länder müssen heute in den verschiedensten Zusammenhängen abrufbar und verwendbar sein. Diese große Bandbreite müssen heutzutage GIS-Systeme abdecken. Um dies zu erreichen entwickelten sich die GIS-Systeme über einen längeren Zeitraum, wobei hier der Zeitraum betrachtet werden soll, in dem sich -3- die Entwicklung mit dem Einsatz von EDV-Systemen völlig neuen Einsatzgebieten öffnete. Bartelme unterteilt diese Entwicklung in seinem Buch [Bar 95] in 5 Phasen. Diese 5 Phasen sind in Abbildung 2.1 auf einer Zeitleiste dargestellt. Hier sind die Phasen aufgeführt die Barteleme benennt. Dem gegenüber sind einige Zeitpunkte von wichtigen Entwicklungsschritten von Hardund Software dargestellt, so dass man eine Gefühl für die entsprechenden Entwicklungen erhält. Abbildung 2.1 Zeitleiste Was charakterisierte die einzelnen Phasen in der Entwicklung der GIS-Systeme ? Die Zeit der Pioniere 1955 bis 1970 war dadurch gekennzeichnet, dass verschiedenste Pioniere individuelle und voneinander isolierte Wege einschlugen. Daten lagen nicht in digitalisierter Form vor und die Entwicklung der Hardware befand sich noch in den Grundlagen. In der Zeit von 1970 bis 1985 begannen die ersten Behörden die Verwaltung von Geodaten auf Computer umzustellen. Von der Funktionalität heutiger Geoinformationssysteme waren diese ersten Umsetzungen noch weit entfernt, aber die ersten entscheidenden Grundlagen wurden gelegt. Die Zeit der Firmen, von 1982 bis 1990, ist gekennzeichnet durch entsprechende Entwicklungen im Software und Hardwarebereich, wie auch aus der Zeitleiste zu ersehen ist. In dieser Zeit wurden grundlegende Entwicklungen getätigt, die bis heute in den GIS-Markt hereinreichen. Firmen wie ESRI entwickelten Arc/Info, Siemens entwickelte Sicad. Die Entwickler auf der Hardwareseite stellten -4- Workstations zur Verfügung, mit denen es möglich wurde die Datenfülle und die Grafikanwendungen zu bewältigen. Dann ab 1988 kann man von der Zeit der Nutzer sprechen. Die Software stand zur Verfügung, die Hardware hatte den Stand erreicht, so dass ein sinnvoller Einsatz gewährleistet war. In Netzwerken war es jetzt möglich Daten und Funktionen sinnvoll zu nutzen. Ab 1995 ist das Zeitalter des Internet angebrochen. Viele neue Anwendungsbereiche entstehen. Daten werden weltweit genutzt. Die Hersteller müssen neue Lösungen entwickeln, denn auch Laien können nun in verschiedensten Anwendungen GIS-Systeme nutzen. Diese neuen Anwendungen sind z.B. Routenplaner, digitale Stadtpläne im Internet oder Navigationssysteme in Autos. Gleichzeitig werden GIS-Systeme aber auch von immer höhere Anzahl verschiedenen Fachrichtungen genutzt, so z.B. von Bauingenieuren zur Straßenplanung oder von Geowissenschaftlern um Daten über Flusssysteme zu analysieren. Aber auch weiterhin setzen Behörden GIS-Systeme ein, um die anfallenden Daten zu speichern. 2.2 Die Elemente eines GIS-Systems Ein GIS-System setzt sich aus verschiedenen Komponenten zusammen. Betrachtet man dazu erst einmal die Definition zu einem GIS-System. [Bil 99/1] Definition : Geo-Informationssysteme „ Ein Geo-Informationssystem ist ein rechnergestütztes System, das aus Hardware, Software, Daten und den Anwendungen besteht. Mit ihm können raumbezogene Daten digital erfasst und redigiert, gespeichert und reorganisiert, modelliert und analysiert sowie alphanumerisch und graphisch präsentiert werden.“ Anhand dieser Definition ist zu erkennen, dass ein Anwender durch Einsatz von Software, Hardware und Daten neue Informationen aus bestehenden Daten gewinnen kann. Diese neu gewonnenen Informationen werden mit Hilfe des gleichen Systems neu aufbereitet und können analysiert werden. Zum besseren Verständnis von beteiligten Personen werden die Daten in verschiedenster Weise -5- präsentiert. Dieses stellt auch direkt die Funktionalität des Modell – View – Controller Musters dar ( siehe auch [BMR 98] ). Das Modell repräsentiert die zur Verfügung stehenden Daten. Der Controller der die Informationen neu zusammensetzt und schließlich der View der die Ergebnisse präsentiert (siehe Abbildung 2.2 ) zeigt, den engen Zusammenhang von Modell – View – Controller Muster, mit dem Aufbau von Geo-Informationssystemen. Abbildung 2.2 Aufbau von MVC bzw. GIS-Systemn Ein besonderes Augenmerk in dieser Definition sollte man auf den Begriff der raumbezogenen Daten legen. Was raumbezogene Daten sind wird im weiteren Verlauf deutlich werden. Zuvor jedoch müssen noch einige Gesichtspunkte des Begriffes der Dimension erläutert werden. Die Abbildung 2.3 Dimensionen von Geometriedaten ( entnommen aus [Bil 99/1] ) stellt dies bildlich dar. -6- Abbildung 2.3 Dimensionen von Geometriedaten Zum besseren Verständnis hier noch einmal die Charakteristika in Worte gefasst. ?? zweidimensional (2D), wenn sich die Geometriedaten nur auf die x,yKoordinaten beziehen und Höhenangaben nicht weiter betrachtet werden. ?? zwei-plus-eindimensional (2D + 1D), wenn die zweidimensionale Darstellung durch eine digitale, durch Höhenlinien, Beschreibung der Geländeoberfläche ergänzt wird. ?? zweieinhalbdimensional (2.5D), wenn zur Lagegeometrie die Höhe z als Attribut gespeichert wird. Dies wird in der Abbildung 2.3 deutlich, da hier keine Höhenlinien gezeichnet werden, sondern einzelne Punkte eine Höhenangabe erhalten. ?? dreidimensional (3D), wenn die x,y,z – Koordinaten mit entsprechender Häufigkeit im gesamten zu bearbeitenden Gebiet vorhanden sind. Wie in der Abbildung zu erkennen ist, wird das 3D Modell nochmals in drei -7- verschiedene Darstellungen aufgeteilt und zwar in 3D-Linienmodell, 3DFlächenmodell und 3D-Volumenmodell. Die verschiedenen Modelle sind verschieden aufwendig und es werden verschiedene Verfahren verwendet die Informationen zu speichern. ?? vierdimensional (4D), zu den Raumkoordinaten x,y,z wird der Zeitparameter (t) abgespeichert. Auch bei den anderen Dimensionen kann der Zeitparameter mit in betracht gezogen werden, so dass man z.B. von 2D + t Datenmodellen spricht. 2.3 Darstellung von Daten In GIS-Systemen müssen verschiedenste Informationen graphisch dargestellt werden. Dazu werden überwiegend Flächen, Punkte und Linien verwendet, die dann die Informationen wiederspiegeln sollen. Aus der graphischen Datenverarbeitung wissen wir, dass es im Endeffekt zwei verschiedene Möglichkeiten der Darstellung gibt. Zum einen die Rasterdarstellung und zum anderen die Vektordarstellung, wobei die Rasterdarstellung auf Pixel aufgebaut ist und die Vektordarstellung auf Punkten und Linien bassiert. In GIS-Systemen werden Vektordaten und Rasterdaten zur Darstellung und Speicherung der Informationen verwendet. Deshalb sollen hier noch einmal die wichtigsten Kriterien zur Verwendung von Vektordaten und Rasterdaten aufgeführt werden, um dann die Frage zu beantworten, wann am effektivsten Rasterdaten bzw. Vektordaten eingesetzt werden. 2.3.1 Vektordaten und Rasterdaten Bei Vektordaten wird von einem Ursprung ausgehend ein Punkt beschrieben, an dem ein Linienzug beginnt. Von diesem Punkt wird wiederum durch einen Vektor der nächste Punkt angegeben u.s.w., bis das gesamt darzustellende Objekt beschrieben ist ( siehe Abbildung 2.4 b ). -8- Bei Rasterdaten werden einzelne Punkte zur Darstellung des Objektes genutzt, wie in Abbildung 2.4 c zu erkennen ist. In Abbildung 2.4 a ist das reale gezeichnete Objekt zu erkennen. Abbildung 2.4 Darstellung eines Objektes in Vektor- und Rasterdarstellung Welche Vorteile bzw. Nachteile haben nun Vektordarstellung und Rasterdarstellung ? Welche Datenmengen treten auf ? Wie steht es mit der Datenerfassung und wo findet sich welche Darstellung in GIS-Systemen wieder ? Bei der Datenerfassung werden verschiedenste Geräte eingesetzt. Ein Gerät, das inzwischen überall Einzug gefunden hat, ist der Scanner. Bei einem Scanner werden zeilenweise einzelne Pixel eingelesen, d.h. der Scanner arbeitet mit der Rastertechnik. Weitere Geräte, die zur Datenerfassung die Rastertechnik einsetzen sind z.B. CDD-Kameras. Der Nachteil, den die Rastertechnik mit sich bringt, sind die großen anfallenden Datenmengen, da jedes einzelne Pixel beschrieben werden muss und dann noch ggf. verschiedenste Farbtöne dem Pixel zugeordnet werden müssen. Hier setzt der große Vorteil der Vektordarstellung ein. Für eine Linie muss nur der Anfangspunkt und der Endpunkt bekannt sein - also zwei Punkte und dieser gesamten Linie kann dann die Farbinformation einmal mitgegeben werden, dies reduziert die Datenmengen erheblich. Weitere Informationen zur Erfassung, Darstellung und Technik von Vektor- bzw. Rasterdarstellung sind zu finden in [Bil 99/1] bzw. in [ESK 96/1]. Betrachten wir nun noch einmal die einzelnen Eigenschaften, die für Vektordarstellung gelten : ?? Punkte und Linien als graphische Grundstruktur, Flächen als geschlossener Linienzug. -9- ?? einfache Änderung von Schraffur, Strichausdehnung und Strichdicke ?? Daten und Objektlinien geordnet, dadurch linienhafte Betrachtung möglich. ?? logische Datenstrukturierung und Objektbezug möglich ?? geringe Datenmenge ?? kurze Rechenzeiten Dem gegenüber stellen wir noch einmal die Eigenschaften der Rasterdarstellung : ?? Pixel als graphische Grundstruktur ?? Flächenhafte Betrachtungsweise ?? Ordnung nur nach der Position der Pixel ?? logische Datenstrukturen und Objektbezug sehr eingeschränkt ?? einfache Datenerfassung, kurze Erfassungszeiten ?? große Datenmengen In GIS-Systemen werden sowohl Vektordarstellungen als auch Rasterdarstellungen verwendet. Dies beginnt bereits bei der Erfassung der Daten und setzt sich dann in der Verarbeitung und der Speicherung dieser fort. Vektordaten werden erfasst in Geländeaufnahmen, Luftbildern und Digitalisierung. Informationsquellen, die Rasterdaten liefern, sind z.B. Satelliten, CCD-Kameras oder Scanner. Diese neuen Informationen werden dann noch mit alphanumerischen Daten oder vorhandenen Sachdaten ergänzt. Die geometrischen Elemente und deren graphische Repräsentation werden, im Bezug auf GIS-Systeme in Abbildung 2.5 verdeutlicht. Diese Abbildung wurde aus [Bil 99/1] entnommen. - 10 - Abbildung 2.5 Geometriedaten und deren graphische Ausgestaltung Aus Abbildung 2.5 kann entnommen werden, dass für Flächen, denen keine weiteren Informationen zugeordnet werden müssen, Rastergrafiken einfacher einzusetzen sind (z.B. Waldgebiete). Dagegen ist die Darstellung einer Bahnlinie in der Vektordarstellung einfacher zu realisieren , Flächen hingegen sind mit Hilfe der Vektorgrafik etwas komplizierter zu beschreiben. Nun stellt sich die Frage, wann werden in GIS-Systemen Vektordaten und wann werden Rasterdaten eingesetzt. Dazu wollen wir uns einmal ein GIS-System etwas näher ansehen. 2.3.2 Maßstäbe Dabei fällt uns auf, dass in einem GIS-System mit verschiedenen Maßstäben gearbeitet wird. Dies ist auch recht einleuchtend, betrachten wir z.B. nur einmal eine Deutschlandkarte. Angenommen wir wollen eine Reise von Köln zum - 11 - Bodensee machen, um dann dort die Gegend zu erwandern. Dazu benötigen wir zwei verschiedene Karten. Zum einen eine Autobahnkarte auf der wir den Weg von Köln zum Bodensee finden - hier haben wir einen kleinen Maßstab von 1 : 400000 - da wir ja nur die Verbindungen via Autobahn von Köln nach Konstanz benötigen. In Konstanz angekommen gehen wir nun auf die Wanderschaft und hier benötigen wir dann einen anderen Maßstab, da uns ja hier Fußwege interessieren, so dass wir hier eine Karte mit einem großen Maßstab von vielleicht 1 : 1000 einsetzen. Ähnlich arbeitet ein GIS-System auch. Zuerst hat man einen kleinen Maßstab, wo dann z.B. ein Land dargestellt wird. Wenn man nun einen Punkt auf dieser Karte immer weiter vergrößert, ändert sich der Maßstab und es ist dann möglich erst Städte, dann einzelne Stadtteile bis hin zu einzelnen Straßen zu erkennen. Wird das GIS-System jetzt z.B. bei einem Energieversorger eingesetzt, kann dies dazu führen, dass einzelne Leitungen für Strom bzw. Gas in der Straße zu erkennen sind. Hierbei muss dann das GIS-System in der Lage sein, von einer Rasterdarstellung in den kleinen Maßstäben zu einer Vektordarstellung in den großen Maßstäben zu skalieren. Wann spricht man von großen, mittleren und kleinen Maßstäben ? Wann werden Vektorgrafik und wann wird Rastergrafik eingesetzt ? Was ist Hybride Grafik ? Auf diese Fragen gibt uns Abbildung 2.6 Auskunft. - 12 - Abbildung 2.6 Maßstäbe Aus Abbildung 2.6 kann man entnehmen, dass es drei verschiedene Kategorien von Maßstäben gibt. Zum einen der große Maßstab mit einer Auflösung von 1 : 500 bis 1 : 10000 , dann einen mittleren Maßstab von 1 : 10000 – 1 : 300000 und als drittes den kleinen Maßstab größer 1 : 300000. Der Abbildung ist weiter zu entnehmen, dass die Vektorgrafik bei großen Maßstäben und die Rastergrafik vorzugsweise bei kleinen Maßstäben eingesetzt wird. Die Hybride Grafik, d.h. der Einsatz von Vektorgrafik oder Rastergrafik, bzw. Mischformen dieser finden ihren Einsatz im Bereich der mittleren Maßstäbe bis hin zu den kleinen Maßstäben. 2.4 Datenspeicherung und Verarbeitung Ein weiterer wichtiger Punkt, der noch erläutert werden muss, sind Strategien zur Datenspeicherung und Verarbeitung. Hier spielt die Datenspeicherung mittels Rasterdaten bzw. Vektordaten ebenfalls eine entscheidende Rolle. Betracht man z.B. eine Karte in der Brunnen aufgeführt sind, so haben wir dies beispielhaft als Punkte gegeben (siehe Abbildung 2.7). - 13 - Abbildung 2.7 Brunnenkarte Wie man nun erkennen kann, sind die Brunnen als Punkte gegeben. Eine weitere Auffälligkeit ist die Häufung der Brunnen. Wie ist es nun möglich diese Daten möglichst einfach und effizient abzuspeichern ? Wenn man ein Raster über die Karte legt erkennt man, dass in einigen Feldern viele und in anderen Feldern ( in diesem Beispiel sogar in der Mehrzahl ) keine Brunnen eingetragen sind (siehe Abbildung 2.8). Abbildung 2.8 Brunnenkarte mit Raster Wie nun zu sehen ist, kann man die Brunnen, die in einem Feld liegen speichern. Man kann also speichern : Brunnen = { A1, C2, B4, E4, E5, F5 } - 14 - Man kennt nun die Felder in denen jeweils Brunnen liegen. Man weiss aber nicht, wie viele Brunnen in dem entsprechenden Feld liegen, bzw. die genaue Position des Brunnens. Diese Situation ist vergleichbar mit einem kleinen Maßstab. Die Anzahl der Brunnen könnte man mit einem zusätzlichen Parameter speichern, so dass man speichern könnte : Brunnen = {A1(5), C2(1), B4(1), E4(4), E5(4), F5(1) } Wenn man nun beginnt das Raster zu verfeinern ist es möglich, die Brunnen sehr genau in der Lage zu bestimmen. Nun steht man vor der Frage, welche effektivere Möglichkeit es gibt, die Brunnen zu speichern. Die Lösung, die angewendet wird, ist der Quadtree. Bei diesem Ansatz wird die Karte zuerst in vier gleichgroße Quadrate aufgeteilt. Diese Quadrate werden dann an den Stellen, wo sich ein Brunnen befindet, weiter verfeinert. Das Ergebnis wird dann mittels eines Baumes gespeichert. Die Aufteilung der Karte in die entsprechenden Quadrate ist in Abbildung 2.9 ersichtlich. Abbildung 2.9 Quadtree-Prinzip In dieser Abbildung ist zu erkennen, dass die genaue Speicherung der Position der Brunnen einen geringeren Aufteilungsaufwand voraussetzt, als die gleiche - 15 - Genauigkeit bei der Aufteilung in gleichgroße Felder, die dann in einer Liste gespeichert werden. Des weiteren ist es möglich, sich auch nur für bestimmte Positionen auf der Karte eine genaue Aufschlüsselung zu erstellen. Nach dieser Betrachtung zur effektiven Speicherung von Punkten, wollen wir nun einmal die Vorgehensweise bei Strecken betrachten. Dazu stellen wir uns vor, wir müssen das Straßennetz eines Ortes daraufhin untersuchen, ob es möglich ist von Punkt A nach Punkt B zu gelangen. Hierzu haben wir wieder eine Karte und die beiden Punkte gegeben (siehe Abbildung 2.10). Abbildung 2.10 Verbindungskarte In der Abbildung sind die Punkte A und B sowie die Wege zu erkennen. Als nächstes legen wir ein Raster über die Karte und speichern die Strecken ab, die von einem Feld des Rasters in ein benachbartes Feld übergehen (siehe Abbildung 2.11). - 16 - Abbildung 2.11 Straßennetz mit Raster Hier wird nun gespeichert welche Verbindungen bestehen. Beginnend mit A1-B1 wird dies entsprechend mit allen Verbindungen durchgeführt. Verbindungen = { A1-B1, B1- B2, B2-C2, C2-C1, C1-D1, A1-A2, A2-B3, B3C3, C3-D3 } Mit Hilfe dieser Verbindungen ist es jetzt möglich festzustellen, ob ein Weg von A nach B existiert. Dazu muss festgestellt werden wo der Punkt A liegt. Punkt A liegt in Feld A1. Dann muss festgestellt werden wo Punkt B liegt. Punkt B liegt in Feld D3. Jetzt muss mit Hilfe eines geeigneten Graphalgorithmus die Liste der Verbindungen durchsucht werden, um festzustellen, ob es eine Verbindung zwischen den Feldern A1 und D3 gibt. Hierzu kann beispielsweise der Algorithmus Topologisches Sortieren oder auch der Algorithmus zum feststellen des kürzesten Weges in Graphen genutzt werden. - 17 - Weiter Informationen zu Graphalgorithmen finden man in [Sed 99] oder [ALG 00]. - 18 - Kapitel 3 Datenbanksysteme In diesem Kapitel wird kurz die Funktionsweise von Datenbanksystemen angerissen und an den Beispielen Oracle und MySQL vertieft. Des weiteren wird erläutert, warum sich im Projekt “Wassermanagement in Chile“ für die Oracle Datenbank entschieden wurde und was dies dennoch an Problemen mit sich brachte. Außerdem wird in diesem Kapitel ein Datenmodell entworfen, das für das Projekt einsetzbar ist. Hierzu werden dann die Entscheidungskriterien diskutiert und zum Abschluss des Kapitels wird noch ein Auszug aus dem Datenmodell modelliert, der dann für das Kapitel 4 ( Technologien mittels Java auf Datenbanken zuzugreifen ) konkret genutzt wird. 3.1 Datenbanksysteme Heute findet man große Datenbankensysteme, die von verschiedenen Herstellern angeboten werden. Es finden sich aber auch inzwischen leistungsstarke Alternativen aus dem Bereich der Open-Source-Software. An dieser Stelle soll nur Oracle für die kommerzielle Seite genannt werden bzw. MySQL für die Seite der Open-Source-Software, da für das Projekt “Wassermanagement in Chile“ auch zwischen diesen beiden Produkten eine Wahl getroffen werden musste. Verdeutlichen wir uns aber zuvor noch einmal kurz, was eine Datenbank ist und was diese leisten muss. Wir finden in [DBS 00] eine entsprechende Definition, die hier kurz wiederholt werden soll : „ Eine Datenbank ist eine Ansammlung von Daten, die allen Benutzern bzw. Anwendungen zur Verfügung steht und in der die Daten nach einheitlichen Regeln abgespeichert werden. Eine Datenbank besteht aus einer Datenbasis und einem Datenbasisverwaltungssystem (DBMS).“ - 19 - Von dieser Definition ausgehend müssen noch die Begriffe Datenbasis und DBMS geklärt werden. Auch hierzu findet man in [DBS 00] entsprechende Definitionen die hier der Vollständigkeit halber noch einmal aufgeführt sind. „ Unter der Datenbasis versteht man die eigentlichen Daten der Datenbank im Dateisystem, also eine gewisse Anzahl von physikalischen Dateien, in denen die Anwendungsdaten und das Data-Dictionary gespeichert sind. Das Data-Dictionary (oder auch Metadaten), enthält Daten, die die Datenbasis z.B. Tabellenstrukturen, definieren. Es beinhaltet außerdem Daten über Verwendung und Bedeutung des Datenmodells, ihre Beziehungen untereinander und Integritätsbedingungen. Das Data Base Managment System (DBMS) ist ein Softwaresystem zur Verwaltung der Datenbasis. Alle Prozesse der Datenbank werden gesteuert und verschiedenen Dienstleistungen zur Verfügung gestellt. Durch eigene Parametrisierung wird das System an spezielle Bedürfnisse angepasst. Dazu gehören z.B. Funktionen zum Speichern der Daten, zur Verwaltung der Ressourcen und Maßnahmen zur Sicherung der Datenkonsistenz. Ein DBMS liegt in der Funktionalität zwischen Anwendungsprogramm und Betriebssystem.“ Anhand dieser Beschreibung kann man sich schon ein recht genaues Bild darüber machen, wie ein Datenbanksystem aufgebaut ist. Tiefer soll an dieser Stelle jedoch der Aufbau eines Datenbanksystems nicht betrachtet werden. Als nächstes sollten die Begriffe “Relationale Datenbank“ und “Objektrelationale Datenbank“ in ihrer Bedeutung klar werden. Dazu findet man in [DBS 00] folgendes : „ Relationale Datenbank Die Daten und ihre Beziehungen werden in Tabellen (Relationen) abgebildet. Eine Tabelle ist horizontal in Zeilen und vertikal in Spalten aufgeteilt. Jeder Datensatz wird als Zeile dargestellt. Die Zeilen heißen Tupel und die Spaltenüberschriften Attribute.“ Anhand dieser Beschreibungen kann man sich nun vorstellen, was eine Datenbank ist und was sie leisten muss. Weiter werden wir an dieser Stelle nicht - 20 - auf Datenbanken eingehen, da diese Grundlagen bereits seit der Datenbankvorlesung bekannt sein sollten. Die beiden Produkte Oracle und MySQL erfüllen diese Voraussetzungen und bieten dem User jeweils eine komplett funktionierendes Datenbanksystem. Was sind nun die entscheidenen Unterschiede von Oracle und MySQL ? MySQL ist ein Open-Source-Produkt, das im Rahmen der beigefügten Lizenzbedingungen genutzt werden kann. MySQL wurde von der schwedischen Consultingfirma TcX entwickelt. Diese benötigten ein flexibles und schnelles Datenbanksystem, das zu dieser Zeit nicht auf dem Markt vorhanden war und so entwickelten sie ihr eigenes System MySQL. Aufgrund der Lizenzbedingungen ist es möglich, MySQL umsonst einzusetzen, was dafür sorgte, dass Universitäten, gemeinnützige Organisationen und Internet Service Provider davon regen Gebrauch machten. Inzwischen wird MySQL auch in der Geschäftswelt eingesetzt. MySQL lässt sich mit Java sowie als auch mit PHP nutzen. Für beides findet man im Internet viele hervorragende Beispiele, um sich der jeweiligen Problematik zu nähern. Im Anhang sind mehrere Internetseiten aufgeführt, die sich mit MySQL, Java und PHP beschäftigen. Hier sind immer wieder aktuelle Informationen zu finden. Weiterhin ist es möglich, sich bei entsprechenden Foren und Newsgroups, Tipps und Informationen zu beschaffen, die bei der Problemlösung helfen können. Eine Einführung in MySQL ist findet man unter anderem in [Mas 01]. Als weiteres Datenbanksystem soll hier stellvertretend für alle anderen Datenbanksysteme kurz Oracle erwähnt werden. Oracle ist ein Datenbanksystem, das inzwischen als Version 9i zu erhalten ist, wobei jedoch die Version 8i im kommerziellen Einsatz die verbreiterte ist, da die Version 9i erst seit Anfang 2002 nutzbar ist. Oracle gehört mit zu den führenden Datenbanksystemen und ist in der Geschäftswelt sehr verbreitet. Für viele Anwendungen findet man spezielle Treiber, mit denen es möglich ist auf Oracle zuzugreifen. Selbst große Anwendungen wie z.B. SAP arbeiten direkt mit Oracle zusammen, bzw. werden so entwickelt, das sie als Datenbank Oracle nutzt. Eine Einführung in Oracle 8i findet man in [ACA 00] oder in [Loc 97], wobei das letztgenannte auch inzwischen für Oracle 9i erschienen ist. - 21 - 3.2 Oracle vs. MySQL Für den Projekteinsatz “Wassermanagement in Chile“ wurde überlegt, welches Datenbanksystem einsetzt werden sollte. Für beide Systeme sprachen verschiedene Punkte, die hier kurz aufgeführt werden sollen. Für MySQL sprachen : ?? geringe Kosten durch das Lizenzmodell ?? weite Verbreitung da Open-Source ?? schnell und für verschiedenste Möglichkeiten konfigurierbar ?? klein und flexibel für den ersten Testeinsatz Gegen MySQL sprachen : ?? keine Unterstützung der Spatial Technologie ?? keine Möglichkeit eine Anbindung an ArcSDE durchzuführen Diese beiden Punkte sorgten schon dafür, das MySQL nicht ausgewählt werden konnte. Für Oracle sprachen : ?? weltweit bekanntes Produkt ?? Umsetzung von Spatial Technologie ?? Anbindung an ArcSDE mittels Treiber möglich ?? Oracle in Campuslizenz zu Testzwecken vorhanden Gegen Oracle sprachen : ?? hohe Anschaffungskosten als Vollprodukt Da jedoch ArcSDE eingesetzt werden sollte, wurde Oracle als Datenbanksystem ausgewählt. Im späteren Einsatz des gesamten Systems muss eine Lösung für die - 22 - Anschaffung des Datenbanksystems Oracle gefunden werden. Dies spielt besonders im Hinblick auf Entwicklungsländer eine entscheidende Rolle, da hier die Kostenseite nicht außer acht gelassen werden darf. 3.3 Ein Datenmodell In diesem Kapitel wird ein Datenmodell entwickelt, welches für den Einsatz im Projekt “Wassermanagement in Chile“ nutzbar wäre. Die Modellierung erfolgt mit dem Tool ErWin, mit welchem dann auch gleich das Skript zur Erstellung der Datenbank erzeugt wird. Dieses Skript ist vollständig im Anhang C zu finden. Hier soll zusammenfassend berichtet werden, warum welche Entscheidungen getroffen wurden. Um festzustellen, was modelliert werden sollte, wurden mehrere Gespräche geführt, die dafür sorgten, dass das Datenmodell immer wieder erweitert wurde. In den ersten Gesprächen wurde ein Pflichtenheft erstellt, dieses ist in Anhang E wiedergegeben. Die wichtigste Entität des Datenmodells ist die Entität Fluss. Dieser Entität sollten verschiedenste Attribute zugeordnet werden. So ist es von Bedeutung, dass der Fluss einen Namen hat. Zur besseren Verwaltung wurde jedem Fluss eine ID zugeordnet, so dass es möglich wird das Modell für mehrere Flüsse, bzw. für Flusssysteme zu nutzen. Bei der Analyse der Entität Fluss zeigte sich, dass jeder Fluss irgendwo entspringt. Dies kann verschiedene Ursachen haben, so z.B. als Quelle, aber auch als Abfluss eines Sees. Diese Möglichkeiten sollten im Datenmodell berücksichtigt werden und werden unter dem Attribut Quellgebiet abgelegt. Des weiteren ist von Bedeutung, wohin der Fluss fließt, auch hier gibt es wieder verschiedene Möglichkeiten. Der Fluss kann in einen See oder in das Meer fließen, es ist aber auch möglich, das der Fluss in einen anderen Fluss mündet, dies wird im Attribut Mündungsgewässer abgelegt. Ein weiteres Attribut der Entität Fluss ist die Länge des Flusses in km. Somit haben wir schon einige Attribute für die Entität Fluss gesammelt und können uns dies in Abbildung 3.1 visuell vor Augen führen. In der Abbildung ist ein weiteres Attribut zu erkennen, das als ’natürlich’ bezeichnet ist, hier kann festgehalten werden, ob es sich um einen Kanal handelt. Wenn dies der Fall ist, würde in natürlich ein ’false’ stehen, um zu zeigen, dass es - 23 - sich um ein künstliches oder besser ein von Menschenhand geschaffenes Gewässer handelt. Weiter sind in der Abbildung 3.1 sofort die Datentypen der Attribute ersichtlich. Abbildung 3.1 Entität Fluss Die nächste Entität, die in diesem Zusammenhang betrachtet werden muss, ist die Entität Gewässer. Wie bei der Entität Fluss wird hier auch wieder eine ID genutzt, sie wird als Gewässer ID bezeichnet und dient unter anderem dazu, die Flüsse den Gewässern zuzuordnen, was in der entsprechenden Entität ’GewässerFluss’ dann vollzogen wird. In der Entität Gewässer findet man die Attribute Namen, für das Gewässer, Fläche in Quadratkilometer sowie Tiefe in Metern, diese Attribute sind bereits durch ihre Namen erklärt. Dieser Teil des Modells ist vollständig in Abbildung 3.2 wiedergegeben. Abbildung 3.2 Modellierung Gewässer - Fluss Zu beachten ist, dass ein Fluss in einen anderen Fluss münden kann, dies müsste dann mit einem Trigger modeliert werden. Als nächstes müssen in das Datenmodell Messpunkte aufgenommen werden, da im Projekt “Wassermanagement in Chile“ an verschiedenen Messpunkten verschiedene physikalische Größen gemessen werden sollen und diese Werte dann in einer Datenbank abgelegt werden sollen. Bei der Analyse dieser Zusammenhänge stellt man fest, dass es möglich wird, mit zwei Hauptentitäten zu arbeiten, zum einen mit der Entität Messpunkt zum andern mit der Entität Messwert. - 24 - Betrachten wir hier zuerst den Messpunkt und verdeutlichen uns erst einmal was ein Messpunkt überhaupt ist. Ein Messpunkt in unserem Fall ist ein konkreter Ort, der irgendwo auf dem Planeten Erde liegt. Punkte auf der Erde können genau mittels Längen- und Breitengrad angegeben werden. Des weiteren ist es wichtig zu wissen, ab wann es einen Messpunkt gegeben hat. Deshalb sollte das Einrichtungsdatum mit in das Datenmodell aufgenommen werden. Wie man der Abbildung 3.3 entnehmen kann, findet man die aufgeführten Attribute im Datenmodell wieder, zusätzlich ist noch eine ID für den Messpunkt aufgeführt und die Fluss ID um eine Beziehung zwischen dem Messpunkt und dem Fluss zu modellieren. Abbildung 3.3 Modellierung Fluss – Messpunkt Anmerkung zur Modellierung : Bei der Modellierung wurde in diesem Fall für den Messpunkt die Attribute Längengrad und Breitengrad mit varchar2(20) als Datentyp definiert. In wieweit sich Längengrad und Breitengrad darstellen lassen, müsste in einer konkreten Implementierung etwas genauer betrachtet werden, oder ob mittels der Spatial Technik eine andere Darstellung gewählt werden kann. Die Spatial Technik wird noch in einem speziellen Kapitel näher betrachtet. Betrachten wir nun, wie in diesem Datenmodell die Messwerte modelliert wurden und wie es möglich, ist andere Messwerte hinzuzufügen. In Abbildung 3.4 sind die beiden Entitäten Messpunkt und Messwert dargestellt. - 25 - Abbildung 3.4 Messpunkt – Messwert Es ist zu erkennen, dass die Entität Messpunkt mit der Entität Messwert erweitert wird. Dabei werden die Attribute Messwert ID zur besseren Verwaltung und der Messzeitpunkt hinzugefügt. Jetzt fehlen nur noch die Messwerte, die in der Datenbank abgespeichert werden sollen. Um dies zu erreichen wird für jede Art von Messwert eine Entität erstellt, die dann den Messwert aufnimmt (siehe Abbildung 3.5) . - 26 - Abbildung 3.5 Verschiedene Messwerte Hier sind nun beispielhaft die Entitäten für Nitrat, PH-Wert, Härtegrad, Pegelstand und Wasserdurchfluss dargestellt. Wenn man nun eine weitere physikalische Größe in der Datenbank speichern möchte, muss dafür nur die Entität erstellt werden und diese in Zusammenhang mit dem Messwert gebracht werden und schon ist es möglich, diese neue Größe ebenfalls zu speichern. Betrachten wir hier noch als Beispiel wie der Nitritwert aufgenommen werden könnte. Dazu muss eine Entität Nitrit erstellt werden. Dieser Entität wird das Attribut Nitritmesswert zugeordnet, die Messwert ID wird von der MesswertEntität übernommen. Abbildung 3.6 zeigt das erweiterte Datenmodell. - 27 - Abbildung 3.6 Erweitertes Datenmodell um den Messwert Nitrit Nachdem nun die Möglichkeiten gegeben sind, Messpunkte einzurichten und Messwerte zu speichern , muss man sich Gedanken darüber machen, wie die Umgebung des Flusses in Betracht gezogen werden muss. Die Region in der der Fluss liegt kann Einflüsse auf die Messwerte nehmen. So ist es z.B. möglich, das durch intensive Landwirtschaft ein hoher Nitratwert auftreten kann. Aus diesem Grund muss in das Datenmodell die umgebende Region mit aufgenommen werden. Auch ist es vielleicht von Nöten die Regionen oberhalb des Messpunktes zu betrachten, was wieder ein Grund dafür ist, diese Informationen mit in die Datenbank aufzunehmen. Dies wird in ähnlicher Weise erreicht, wie die Modellierung der Messwerte. Zuerst wird eine Entität Region geschaffen und über eine weitere Entität wird dann die Verbindung Fluss und Region modelliert ( siehe Abbildung 3.7 ). - 28 - Abbildung 3.7 Fluss – Region Nun wird die Entität Region mit weiteren Entitäten erweitert, so dass verschiedene Besonderheiten der einzelnen Regionen abgebildet werden können. In diesem Datenmodell wurden ersteinmal nur vier verschiedene Regionsarten unterschieden. Die Unterscheidung wurde aufgeschlüsselt in : Stadt, Industrie, Agrarwirtschaft und Viehwirtschaft. Wenn nun eine andere Differenzierung gefordert würde, müssten entsprechende Entitäten erstellt werden, dies würde genauso erfolgen wie in dem oben bereits gezeigten Beispiel für die Messwerte. In Abbildung 3.8 ist die derzeitige Aufschlüsselung wiedergegeben. Abbildung 3.8 Spezifikation der Region - 29 - In Abbildung 3.8 sind neben der Entität Region, die weiteren Entitäten Agrarwirtschaft, Industrie, Stadt und Viehwirtschaft zu erkennen. Die Entität Region besitzt die Attribute Regions ID, als Schlüssel, sowie die Attribute Bezeichnung und Fläche in Quadratkilometer. Diese Entität wird dann durch die anderen vier Entitäten ergänzt, die dann spezifische Attribute in das Datenmodell einbringen. Für die Agrarwirtschaft ist es wichtig zu wissen, wie groß die Anbaufläche ist, welches Produkt angebaut wird und noch wie viele Arbeitnehmer beschäftigt sind. Bei Industrievorkommen kann die Art der Industrie, Schwerindustrie oder Automobilbau, eine Rolle spielen. Auch kann hier die Arbeitnehmerzahl von Bedeutung sein, so dass diese in das Datenmodell aufgenommen wurde. Im Bereich der Viehwirtschaft ist natürlich ein entscheidendes Attribut die Viehart, die gehalten wird. Bei der Modellierung der Stadt stechen neben der Einwohnerzahl noch die Attribute Vorwahl und Stadt, als Namen der Stadt, ins Auge. Diese Attribute wurden in Hinsicht auf die Verwaltungsbehörden mit in das Datenmodell aufgenommen. Die Verwaltungsbehörden werden als nächstes in diesem Datenmodell betrachtet werden. Jeder Fluss, bzw. jedes Gewässer, kann eine Verwaltungsbehörde besitzen. Diese Verwaltungsbehörden haben ihren Sitz meist in größeren Städten der Region. In den Verwaltungsbehörden ist eine Person als Ansprechpartner für das Gewässer bekannt. Die Verwaltungsbehörde besitzt eine Adresse und es können verschiedene Rufnummern auftreten. Diese Problematik muss ebenfalls in das Datenmodell aufgenommen werden. Dabei ist darauf zu achten, das bereits eine Stadt im Datenmodell vorhanden ist und diese Informationen müssen alle ineinander übergreifen. Abbildung 3.9 Modellierung Verwaltungsbehörde - 30 - In Abbildung 3.9 ist das entsprechende Datenmodell zur Verwaltungsbehörde zu erkennen. Dabei sind die beiden bereits bekannten Entitäten Fluss und Stadt noch einmal mit aufgeführt worden, um den Zusammenhang besser zu verdeutlichen. In der Abbildung ist zu erkennen, dass einem Fluss eine entsprechende Verwaltungsbehörde zugeordnet wird, diese Entität Verwaltungsbehörde besitzt als Attribut den Ansprechpartner. Diesem Ansprechpartner muss jetzt noch die Adresse und entsprechende Telefonnummern zugeordnet werden, dies geschied mittels der Entitäten Adresse und Telefon. Abschließend muss der Adresse noch eine Stadt zugeordnet werden. Die Entität spielt für die Entität Telefon in der Hinsicht eine entscheidende Rolle, dass eine Stadt immer eine feste Vorwahl besitzt und diese mit der Stadt gekoppelt ist und diese Vorwahl dann natürlich in der Entität Stadt gespeichert werden muss. Abbildung 3.10 zeigt noch einmal das gesamte Datenmodell, das hier bereits erläutert wurde. Abbildung 3.10 Gesamtes Datenmodell - 31 - Da dieses gesamte Datenmodell zur Demonstration von Datenbankzugriffen etwas zu umfangreich ist, wird ein kleineres Datenmodell entwickelt, welches dann in Kapitel 4 genutzt werden kann, um die Funktionalität der Software zu demonstrieren. Das gesamte Skript, von beiden Datenmodellen, sowie die Erzeugung von Demodaten ist in Anhang C wiedergegeben. Abbildung 3.11 zeigt das kleine Datenmodell. In diesem Datenmodell wird eine Reduzierung der Messwerte durchgeführt, da die Technik bei zugriff auf die Messwerte bei allen gleich ist, wird dies nur Beispielhaft an einem , in diesem Fall Messwert, demonstriert. Des weiteren sind die Regionen stark eingeschränkt worden, da es sich hier auch nur um eine beispielhafte Darstellung handeln soll. Abbildung 3.11 kleines Datenmodell 3.4 Die Oracle Spatial Technologie In diesem Kapitel ist der Begriff “Oracle Spatial Technologie“ schon des öfteren gefallen. Diese Technologie soll nun etwas genauer betrachtet werden. In der Oracle Spatial Technologie wird ein objektrelationaler Ansatz verfolgt, der es Oracle 8i ermöglicht, mehrdimensionale räumliche Daten zu speichern, zu verarbeiten, zu analysieren und zu manipulieren. Um dies zu lösen stehen dem User etliche Funktionen und Prozeduren zur Verfügung. Wie schon zu erwarten war, ist der hauptsächliche Einsatzbereich der Oracle Spatial Technologie im Bereich von GIS-Systemen angesiedelt. Andererseits richtet sich die Oracle Spatial Technologie an Unternehmen, die ihre Anwendungen um eine geographische Komponente erweitern wollen und primär dann Daten - 32 - visualisieren wollen. Derartige Anwendungen sind häufig Bestandteile von Data Warehouse Lösungen und umfassen Möglichkeiten der raumbezogenen Auswertung, z.B. für Marketingplanung, Umsatzanalysen oder Standortplanungen. 3.5 Der Objekttype GEOMETRY Die Oracle Spatial Technologie unterstützt drei einfache geometrische Datentypen, welche in Abbildung 3.12 dargestellt sind. Zur Umsetzung verfolgt Oracle das Objektrelationale Datenmodell, auf das nun eingegangen werden soll. Abbildung 3.12 Einfache geometrische Datentypen Bei der Umsetzung der Spatial Technologie hält sich Oracle an die Vorgaben der OGC ( Open GIS – Consortium ). Um die Geometrien in der Datenbank ablegen zu können, wird in der Spatial Cartridge der Objekttyp “SDO_GEOMETRY“ angelegt. Dieser setzt sich aus mehreren Elementen zusammen. Diese Elemente sind : ?? SDO_GTYPE ?? SDO_SRID ?? SDO_POINT_TYPE ?? SDO_POINT ?? SDO_ELEM_INFO ?? SDO_ORDINATES - 33 - Nun stellt sich die Frage, was sich hinter dem Objekttypen GEOMETRY verbirgt. Betrachten wir den Objekttypen genauer : ?? SDO_GEOMETRY, wird von der OGC vorgegeben. Die Definition für SDO_GEOMETRY lautet : CREATE TYPE SDO_GEOMETRY AS OBJECT ( SDO_GTYP NUMBER, SDO_SRID NUMBER, SDO_POINT SDO_POINT_TYPE, SDO_ELEM_INFO MDSYS.SDO_ELEM_INFO_ARRAY, SDO_ORDINATES MDSYS.SDO_ORDINATE_ARRAY); Was verbirgt sich hinter den einzelnen Elementen ? Dazu betrachten wir die einzelnen Elemente genauer : ?? SDO_GTYPE, legt den Geometrie Type fest. D = Dimensionszahl, wird durch die Beispiele weiter unten deutlich (siehe Tabelle 3.1 SDO_GTYPE Werte). ?? SDO_SRID, wird zur Zeit nicht genutzt, ist aber reserviert für die spätere Angabe eines räumlichen Bezugssystems. ?? SDO_POINT_TYPE ist ein einfacher Typ aus drei Werten, der einen dreidimensionalen Punkt repräsentiert. Zur Zeit werden nur zwei Dimensionen unterstützt. ?? SDO_POINT wird nur verwendet, falls ein Wert vorliegt und die weiteren Dimensionen den Wert “NULL” erhalten sollen. ?? SDO_ELEM_INFO wird mit SDO_ORDINATES zusammen verwendet. SDO_ELEM_INFO ist ein Feld von Zahlen und gibt an wie die Werte in SDO_ORDINATES zu verwenden SDO_ORDINATES ist ebenfalls ein Feld von Zahlen. - 34 - sind. Wert Geometrieart Beschreibung D000 UNKNOWN_GEOMETRY wird ignoriert D001 POINT Punkt D002 LINESTRING Streckenzug D003 POLYGON Polygon mit oder ohne Öffnung D004 COLLECTION Sammlung von Elementen D005 MULTIPOINT mehrere Punkte D006 MULTILINESTRING mehrere Streckenzüge D007 MULTIPOLYGON mehrere disjunkte Polygone Tabelle 3.1 SDO_GTYPE Werte Betrachten wir einmal was mit dem Objekttypen GEOMETRY und seinen Elementen möglich ist. - 35 - Beispiel 1 : ein einfaches Rechteck. Abbildung 3.13 Rechteck Das in Abbildung 3.13 gegebene Rechteck soll mittels der Spatial Technologie in einer Datenbank gespeichert werden, dazu wird die SDO_GEOMETRY Definition mit Werten gefüllt. SDO_GEOMETRY Column = ( SDO_GTYPE = 2003 SDO_SRID = NULL SDO_POINT = NULL SDO_ELEM_INFO = (1,1003,3) SDO_ORDINATES = (12,15,15,24) ) Betrachten wir nun einmal die eingesetzten Werte : Bei SDO_GTYPE finden wir den Wert 2003, wie kommt man auf diesen Wert ? Da wir ein Polygon im zweidimensionalen betrachten, bekommt man als Dimensionszahl D = 2. Aus der Tabelle 3.1 können wir für das Polygon den Wert 003 entnehmen. Somit erhält man den Wert 2003. SDO_SRID wird aus bekannten Gründen auf “NULL“ gesetzt, was ebenfalls mit SDO_POINT getan wird. Das Tripel von SDO_ELEM_INFO setzt sich wie folgt zusammen. Der erste Wert gibt an, bei welchem Wert von SDO_ORDINATES die Bearbeitung beginnt. Der Wert 1003 gibt an, das es sich um das äußerste Polygon handelt, dies wird in Beispiel 2 klarer. Der letzte Wert dieses Tripel die 3 gibt an, dass es sich bei der - 36 - Figur um ein Rechteck handelt, bei dem nur die Ecke links unten und die Ecke rechts oben angegeben sind. In SDO_ORDINATES sind die Koordinaten der beiden Punkte angegeben, zum einen (12,15) zum anderen (15,24). Es wäre natürlich möglich, dasselbe Rechteck auf eine andere Weise zu beschreiben. Betrachten wir diese Möglichkeit : SDO_GEOMETRY Column = ( SDO_GTYPE = 2003 SDO_SRID = NULL SDO_POINT = NULL SDO_ELEM_INFO = (1,1003,1) SDO_ORDINATES = (12,15,15,15,15,24,12,24,12,15) ) Als erstes erkennt man, dass diesmal viel mehr Koordinaten angegeben wurden. Woran liegt das ? In der SDO_ELEM_INFO wurde der dritte Wert auf 1 gesetzt. Dies besagt, dass einzelne Punkte eines Polygonzuges angegeben werden. Dabei ist darauf zu achten, dass für ein geschlossenes Polygonzug der letzte angegebene Punkt mit dem ersten angegebenen Punkt übereinstimmt. Also sind dann hier in SDO_ORDINATES die einzelnen Eckpunkte des Polygons angegeben. Weitere Informationen zu SDO_ELEM_INFO findet man in der Oracle Spatial User’s Guide and Reference. - 37 - Beispiel 2 : ein Polygon mit einer Öffnung Abbildung 3.14 Polygon mit rechteckiger Öffnung Die gegebene Geometrie soll nun auch wieder mittels des Objekttyps “GEOMETRY“ beschrieben werden, um den Inhalt des Tripels des Element SDO_ELEM_INFO besser verstehen zu können. SDO_GEOMETRY Column = ( SDO_GTYPE = 2003 SDO_SRID = NULL SDO_POINT = NULL SDO_ELEM_INFO = (1,1003,1, 19,2003,1) SDO_ORDINATES = (12,13,15,13,17,15,17,24, 15,26,12,26,10,24,10,15, 12,13, 12,15,15,15,15,24,12,24, 12,15) ) Schauen wir uns nun das Element SDO_ELEM_INFO an. Man erkennt, das hier zwei Tripel angegeben wurden. Das erste Tripel beschreibt die Informationen für das äußere Polygon. Die 1 steht dafür, dass die Werte ab Position 1 beginnen. 1003 gibt an, dass es sich um ein äußeres Polygon handelt und die nächste 1 gibt an, dass es sich um Punkte handelt, die aufgeführt sind. Das zweite Tripel beschreibt die Informationen für das innere Polygon. Die 19 gibt an, dass die Beschreibung des Polygons mit dem neunzehnten Wert beginnt. 2003 besagt, - 38 - dass es sich um ein inneres Polygon handelt und die 1 besagt wieder, dass es sich um einzelne Punkte handelt. Es wäre auch wieder möglich die Geometrie anders zu beschreiben. Da es sich bei der Öffnung um ein Rechteck handelt, kann natürlich auch die Beschreibung wie aus Beispiel 1 erfolgen (siehe nachfolgende Beschreibung). SDO_GEOMETRY Column = ( SDO_GTYPE = 2003 SDO_SRID = NULL SDO_POINT = NULL SDO_ELEM_INFO = (1,1003,1, 19,2003,3) SDO_ORDINATES = (12,13,15,13,17,15,17,24, 15,26,12,26,10,24,10,15, 12,13, 12,15,15,24) ) Abschließend soll noch gezeigt werden, wie effizient es mit diesem Ansatz ist, die Figur aus Abbildung 3.15 zu beschreiben. Abbildung 3.15 Rechteckprofil SDO_GEOMETRY Column = ( SDO_GTYPE = 2003 - 39 - SDO_SRID = NULL SDO_POINT = NULL SDO_ELEM_INFO = (1,1003,3, 5,2003,3) SDO_ORDINATES = (10,13,17,26, 12,15,15,24) ) 3.6 Indexing Die Techniken, die im Abschnitt Datenspeicherung und Verarbeitung gezeigt wurden, werden auch in der Oracle Spatial Technologie umgesetzt. Hier findet man zum einen das “fixed indexing“, das mit einer festen Rasterung arbeitet und zum anderen das “hybrid indexing“, das die Technik des Quadtree verwendet. Betrachten wir nun, wie diese Technik in der Oracle Spatial Technologie umgesetzt wurde. Um eine geometrische Figur in einem Feld darzustellen benötigt man ein Raster. In der Spatial Technologie wird für die Rasterung eine bestimmte zählweise eingeführt. Ein Quadrat wird immer wieder in kleinere Quadrate aufgeteilt. Dabei werden diese Quadrate immer nach derselben Methode nummeriert. Das unterste linke Quadrat erhält die 0. Das Quadrat rechts neben der 0 erhält die 1. Über der 0 liegt die 2 und über der 1 die 3, entsprechend wird ein Raster durchnummeriert (siehe Abbildung 3.16). Abbildung 3.16 Rasterung - 40 - Bei einem “fixed indexing“ wird diese Rasterung beibehalten und die Felder in denen die Endpunkte einer Figur liegen werden gespeichert. Das Problem liegt aber im Aufwand der getrieben werden muss, um eine weitere Verfeinerung der Rasterung zu erhalten, dies führt zu sehr hohem Rechenaufwand. Das “hybrid indexing“ nutzt die Idee des Quadtree, siehe auch Kapitel 2.4. Hierbei wird die Nummerierung etwas anders ausgeführt. Die gesamte Fläche wird in vier gleich große Quadrate aufgeteilt, die dann die Nummern 0 bis 3 erhalten. Die Felder die einen Endpunkt enthalten werden entsprechend verfeinert, wobei z.B. das Quadrat 3 wieder verfeinert wird und in vier gleiche Quadrate aufgeteilt wird, die dann als 30, 31, 32 und 33 bezeichnet werden. Diese Verfeinerung kann bis zu einer beliebigen Genauigkeit durchgeführt werden (siehe Abbildung 3.17). Abbildung 3.17 hybrid indexing In Abbildung 3.17 ist zu erkennen, dass die Rasterung nur an den Punkten durchgeführt wird, an denen ein Endpunkt der Figur liegt. Die Felder werden bestimmt, wobei die Anzahl der Ziffern von der Genauigkeit herrührt. Um z.B. den Punkt in Feld 0002 genauer zu beschreiben, würde das Feld wieder in vier Quadrate geteilt werden und die Bestimmung würde dann 00021 ergeben. - 41 - 3.7 Weitere Aspekte der Spatial Technologie Die Oracle Spatial Technologie beinhaltet weitere verschiedenste Aspekte, die hier nur kurz erwähnt und nicht weiter betrachtet werden sollen. ?? Anfragemodell für räumliche Anfragen ?? Funktionen und Operatoren des Cartridge Oracle Spatail ?? Anfrageoptimierung Im nachfolgenden Kapitel soll nun gezeigt werden, wie es mittels Java möglich ist, auf Datenbanken zuzugreifen und die gespeicherten Informationen über Java aufzubereiten und darzustellen. 3.8 Was bewirkt die Spatial Technologie Durch den Einsatz der Spatial Technologie ändert sich am Datenmodell zunächst nichts. Die Speicherung der Daten wird jedoch effektiver unterstützt. Was bedeutet das ? Zunächst einmal wird ein Punkt zumindestens zweidimensional abgespeichert, d.h. ein x-Wert und ein y-Wert. Interessanter sind die Möglichkeiten Landesgrenzen mittels der Spatial Technologie in Datenbanken abzulegen. Das Land, dessen Grenzen abgespeichert werden sollen, wird als Polygon betrachtet. Beginnend an einem beliebigen Punkt können nun die Aussengrenzen des Landes mittels des Polygons, welches mittels der Spatial Technologie beschreibbar wird, in die Datenbank abgelegt werden. Wenn nun die Daten abgerufen werden, können mit deren Hilfe die Aussengrenzen des Landes gezeichnet werden. Desweiteren ist es möglich, Städte als Punkte in der Fläche des Polygons abzulegen; Straßen und Flüsse wären als Linienzüge ablegbar. So wird es möglich, die gesamten Informationen die in einer Karte enthalten sind, in eine Datenbank abzulegen. Außerdem gewinnt man die Möglichkeit, die Daten die auf oben beschriebene Weise in Datenbanken abgelegt sind, mit weiteren Daten, z.B. Grafiken und Bilder, die ebenfalls in Datenbanken abgelegt sind zu kombinieren. Betrachtet man das Beispiel der Brunnenkarte aus dem Kapitel 2.4, so kann es möglich werden, dass ein Satelitenfoto einer Region als Blob in einer Datenbank abgelegt wird und die Brunnen dann als Punkte mittels der Spatial Technologie gespeichert - 42 - werden. Sämtliche Umrechnungen, die für das verändern des Maßstabes von Nöten wären, müssten jedoch noch näher betrachtet werden. Aber auch für andere Einsatzgebiete bietet die Spatial Technologie die Möglichkeit Daten in Datenbanken abzulegen, so wird es z.B. möglich technische Zeichnungen entsprechend aufzuschlüsseln und so in Datenbanken abzulegen. Die Spatial Technologie stellt eine interessante Möglichkeit dar geometrische Informationen als zusammengehörige Objekte in Datenbanken abzulegen, ohne diese als Grafiken zu speichern. - 43 - Kapitel 4 Technologien mittels Java auf Datenbanken zuzugreifen In diesem Kapitel werden zwei Technologien beispielhaft vorgestellt, mit denen es möglich wird auf Datenbanken zuzugreifen, die der Nutzer sofort - ohne weiteres Hintergrundwissen - in die Lage versetzen die Datenbank zu nutzen. Dabei wird in beiden Möglichkeiten der Datenbankzugriff mittels JDBC durchgeführt. Im ersten Beispiel wird jedoch die Benutzeroberfläche mittels SWING implementiert. Im zweiten Beispiel werden Java Server Pages verwendet, dies wird jedoch nur skizenhaft aufgezeigt. Für beide Technologien ist es wichtig, dass man die Systemarchitektur und den grundlegenden Ablauf des Zugriffs auf das Datenbanksystems klar vor Augen hat. Aus diesem Grund wird hier der Einstieg in dieses Kapitel über die Systemarchitekturen gewählt. Daran schließt sich eine kurze Betrachtung über den prinzipiellen Ablauf einer Datenbankabfrage an, damit die Abläufe klar werden. Mit einer Betrachtung der vier Treibertypen wird diese kurze Zusammenfassung der Grundlagen beendetn um dann den praktischen Einsatz anhand der Beispiele zu verdeutlichen.. 4.1 Systemarchitekturen Prinzipiell findet man bei den Systemarchitekturen zwei Modelle. Zum einen die 2-Schichten-Architektur (two-tier-systems) und zum anderen die 3-SchichtenArchitektur (three-tier-systems). Bei beiden Systemen handelt es sich um sogenannte Client-Server-Architekturen, d.h. der Client stellt eine Anfrage (ggf. über ein Netzwerk) an den Server, dieser bearbeitet die Anfrage und sendet die Antwort dann wieder über das Netzwerk zum Client zurück. Dies setzt die 2-Schicht-Architektur auch direkt so um. Der Client kommuniziert direkt mit der Datenbank (siehe Abbildung 4.1). - 44 - Abbildung 4.1 – 2 – Schichten Architektur Aus welchen Gründen wählt man die 2-Schichten-Architektur ? Die 2-Schichten-Architektur ist leicht zu implementieren, so dass man schnell einmal etwas testen kann. Ein weiterer Vorteil ist, dass sie in der Regel schneller als eine 3-Schichten-Architektur ist. Dies spielt z.B. bei Antwortzeiten eine entscheidende Rolle. Der Nachteil dieser Architektur liegt in der Sicherheit. Da Datenbank und WebServer auf einem Rechner laufen, der dann ggf. aus dem Internet ( wenn dieses als Netzwerk eingesetzt wird ) sichtbar ist. Um diese Sicherheitslücke zu schließen, wurde die 3-Schicht-Architektur entwickelt. Hierbei werden die Aufgaben des Servers auf zwei Rechner verteilt. Auf einem Rechner wird die Datenbank betrieben und um diese zu schützen wird der zweite Rechner zwischen den Datenbankrechner geschaltet. und das Netzwerk Er wird dann als Anwendungs-Server bezeichnet und der Datenbankrechner als Datenbank-Server (siehe Abbildung 4.2). Abbildung 4.2 – 3-Schichten-Architektur Wie in der Abbildung zu erkennen ist, wird auf dem Anwendungs-Server eine sogenannte Middleware verwendet. Diese Middleware sorgt für die Verbindung - 45 - zwischen dem Datenbank-Server und dem Netzwerk, bekannt als Middleware ist z.B. CORBA. Durch den Einsatz der Middleware ist die Sicherheitslücke, die die 2-SchichtenArchitektur beinhaltet geschlossen worden, dadurch treten jedoch längere Laufzeiten für Anfragen des Clients zur Datenbank auf. Ein weiterer Vorteil ist die klare Trennung in die 3-Schichten, ähnlich dem Modell – View – Controller Konzept. Die Präsentation, vergleichbar mit dem View, finden man auf dem Client wieder. Geschäfts-Logik die auf dem Anwendungs-Server umgesetzt wird ist vergleichbar mit dem Controller, der Modell und View miteinander verbindet. Der Datenbank-Server hält die darzustellenden Daten vor und liefert auf Anforderung diese dem Client zur Darstellung.. 4.2 Prinzipieller Ablauf einer Datenbankabfrage mittels JDBC Die Datenbankabfrage mittels JDBC gliedert sich in ihrem Ablauf in fünf Stationen. Als erstes muss der Datenbank-Treiber geladen werden, mit dessen Hilfe dann eine Verbindung zur Datenbank aufgebaut wird. Nachdem dann die Verbindung fehlerfrei aufgebaut wurde, wird in der zweiten Phase das SQLStatement erzeugt. Diese Statement wird dann in der dritten Phase der Datenbank zur Ausführung übergeben. Wie allgemein bekannt ist, löst jedes SQL-Statement in der Datenbank eine Reaktion aus. Diese Reaktion zu verarbeiten ist dann Aufgabe der vierten Phase, in welcher die Ergebnismenge ausgewertet wird. Die letzte Phase in diesem Ablauf stellt das Schließen der Verbindung dar. Betrachten wir nun die einzelnen Phasen in der Hinsicht etwas genauer, welchen Code wir hier implementieren und welche Probleme jeweils auftreten können. 1.Phase : DB-Treiber laden und DB-Verbindung herstellen. Als erstes muss der Datenbanktreiber geladen werden. Dazu muss man diesen zunächst auf dem System identifizieren. Bei Oracle - der hier in den Beispielen verwendeten Datenbank - finden wir diesen in folgendem Unterverzeichnis : oracle/ora81/jdbc/lib/ . Hier sind mehrere Zip - Dateien zu finden. Unser Interesse richtet sich auf die Dateien Classes111 und Classes12. Wir verwenden Classes12 da wir mit dem SDK1.3.1, oder später, arbeiten. Classes111 - 46 - wird verwendet, wenn man ein JDK1.1 oder ein wenn Applets programmiert, die noch mit einem 1.1 Java lauffähig sein sollen und auch wenn noch ältere Runtime - Umgebungen verwendet werden sollen. So finden wir unsere erste Codezeile zur Datenbankanbindung : Class.forName("oracle.jdbc.driver.OracleDriver"); Da hierbei der Fehler auftreten kann, dass der Treiber nicht gefunden wird und diese auch als Exception auftreten kann, muss das Laden des Treibers mit der dazugehörgen Exception in einen try und catch – Block gefasst werden. Dabei handelt es sich um eine „Class Not Found Exception“. Des weiteren muss als nächstes die Verbindung zur Datenbank hergestellt werden. Dazu benötigen wir die Informationen der URL, des Users und das dazugehörige Passwort. User und Passwort sind dieselben, die man auch zur Nutzung einer Datenbank mittels SQL benötigt. Von Bedeutung ist noch die URL. Wie kommen wir an diese ? In einem größeren System, das von einem Administrator verwaltet wird, wenden wir uns an diesen und erhalten unsere gewünschte Information. Wie sieht es in Systemen aus, wo wir selbst der Administrator sind, bzw. wie setzt sich die URL zusammen ? Dazu erst einmal eine typische, später in den Beispielen verwendetet URL : "jdbc:oracle:thin:@localhost:1521:rsz". Was ist an dieser URL zu beachten? Zunächst einmal der Rechnername. Dieser wird nach dem @ angegeben und ist in dieser Testumgebung localhost. Er kann aber auch eine IP-Nummer sein oder ein Rechnername zu einer zugehörigen IPNummer. Danach ist noch der Port angegeben, auf den der Listener der Datenbank ‚hört’. 1521 ist dabei der Port der automatisch bei einer Standartinstallation von Oracledatenbanken eingerichtet wird.. Es kann aber auch vorkommen, dass ein ganz anderer Port einem Listener zugeordnet wurde. Diese muss dann in der Konfiguration der Datenbank nachgeschaut werden. Nach dem Port wird noch die SDI der Datenbank angegeben ( in diesem Beispiel rsz ). Auch hierbei können wieder Fehler auftreten, wie z.B. das eine falsche URL, User oder Passwort angegeben wird, so dass auch hier wieder die Anweisung in einen try- und catch-Block gefasst werden muss. Die Exception die auftreten kann ist eine SQL-Exception. - 47 - Damit ist die erste Phase beendet und wir kommen zur zweiten Phase. 2. Phase : SQL-Statement erzeugen In dieser Phase muss das zu erzeugende Statement mit den Daten zum Zugriff auf die Datenbank verbunden werden. Dies ist eine vorgegebene Aktion, die nicht weiter besprochen werden muss. Der zu erzeugende Code beinhaltet hauptsächlich folgende Codezeile : v_statement = v_connection.createStatement(); wobei v_connection ein Objekt der Verbindung zur Datenbank darstellt. Hierbei können keine weiteren Probleme auftreten, wenn in Phase 1 alles richtig lief. In der dritten Phase wird das Statement ausgeführt. 3. Phase : SQL-Statement ausführen In dieser Phase wird das Statement an die Datenbank zur Ausführung übergeben. Hierbei ist darauf zu achten, dass wenn z.B. eine select - Abfrage getätigt wird, auch die entsprechend richtige Syntax verwendet wird. Da es sich um SQLAnweisungen handelt, kann auch hier wieder eine SQL-Exception auftreten, so dass diese Anweisung auch wieder in einen try- und catch-Block gefasst werden muss. Bei der Implementierung ist vor allem darauf zu achten, dass die SQLAnweisung am Ende als ein gültiger String der Datenbank zur Ausführung übergeben wird, da es sonst zu Fehlern kommen kann, die einige Verwunderungen hervorrufen können. 4. Phase : Ergebnismenge auswerten In dieser Phase ist vor allem darauf zu achten, das Ergebnismengen auftreten können, die nicht beabsichtigt sind, diese müssen dann entsprechend abgefangen und bearbeitet werden. Die richtigen Ergebnisse müssen aber auch zur Weiterverarbeitung entsprechend bearbeitet werden. - 48 - 5. Phase Statement/Verbindung schließen Abschließend muss dann noch das Statement, das in Phase 2 geöffnet wurde, geschlossen werden, um dann als letztes die Verbindung zur Datenbank aus Phase 1 zu schließen. Eine Übersicht über den Ablauf sowie die verwendeten Klassen und die auftretenden Exceptions ist in Abbildung 4.3 zu finden. 4.3 - Ablauf JDBC Anbindung 4.3 Typen von JDBC – Treibern In Java findet man 4 Typen von JDBC – Treibern, die eng mit der Entwicklung des JDBC’s verbunden sind. Bei Sun waren sich die Entwickler von Java sehr schnell bewusst, welches Potential in Java verborgen liegt und welche Möglichkeiten damit verbunden sind, d.h. die plattformunabhängige Entwicklung und auch die Vernetzung verschiedenster Rechnertypen. Da es zur Zeit der Entwicklung bereits ODBC gab und dieses auch im Bereich von C/C++ Programmierung eingesetzt wurde und wird, wollte man natürlich dieses nutzen. - 49 - ODBC ist jedoch schwer zu lernen und ODBC stützt sich auch auf Pointer, die es so in Java nicht gibt. Also musste eine Möglichkeit gefunden werden, eine Datenbankanbindung mittels ODBC und Java zu realisieren. So entwickelten sich die Typ 1-Treiber ( weiteres siehe unten ). Eine andere Möglichkeit war es über den nativen Code mit der Datenbank zu kommunizieren. Damit geht aber die Plattformunabhängigkeit verloren. Dennoch wurde dies in den Typ 2-Treibern realisiert. Type 3-Treiber und Typ 4-Treiber entwickelten sich etwas später, da diese speziell auf und mit Java zugeschnitten wurden. Eine Übersicht über die Treiber findet man in [HC 99/2] : „ ?? Ein Typ 1-Treiber übersetzt JDBC nach ODBC und stützt sich auf einen ODBC-Treiber, um mit der Datenbank zu kommunizieren. Sun bietet im JDK mit der JDBC/ODBC –Brücke einen derartigen Treiber an. Allerdings unterstützt die Brücke nicht JDBC2 und erfordert einen geeignet konfigurierten ODBC-Treiber. Die Brücke ist vor allem praktisch um Datenbankverbindungen zu testen, empfiehlt sich aber nicht für den Produkteinsatz. ?? Ein Typ 2-Treiber ist zum Teil in Java geschrieben und stützt sich auf nativen Code, der mit der Client – API einer Datenbank kommuniziert. Wenn man mit einem derartigen Treiber arbeitet, muss man neben einer Java-Bibliothek auch plattformspezifischen Code installieren. ?? Ein Typ 3-Treiber ist eine reine Client-Bibliothek in Java, die über ein datenbankunabhängiges Protokoll Datenbankanforderungen an eine Serverkomponente schickt, die wiederum die Anforderungen in ein datenbankspezifisches Protokoll umsetzt. Die Client-Bibliothek ist unabhängig von der eigentlichen Datenbank und vereinfacht somit die Entwicklung. ?? Ein Typ 4-Treiber ist eine reine Java-Bibliothek, die JDBCAnforderungen direkt in ein datenbankspezifisches Protokoll übersetzt.“ In Abbildung 4.4 sind noch einmal die 4 Typen dargestellt. Des weiteren ist die Kommunikation von der Anwendung über die JDBC-API über den Treibermanager, der wiederum auf die Treiber -API zugreift, dargestellt. Die Treiber – API kommuniziert dann mit den einzelnen Treibertypen, die dann die - 50 - Verbindung zur Datenbank herstellen. Die Rückkommunikation erfolgt dann auf dem umgekehrten Wege. Abbildung 4.4 – JDBC – Treibertypen und Kommunikation Anwendung – DB Nachdem nun einige grundlegende Ding über JDBC noch einmal zusammengetragen wurden, werden wir nun zu einer ersten Anwendung kommen. 4.4 Datenbankzugriffe unter Nutzung von Swing Anhand einer Beispiel Implementierung soll nun gezeigt werden, wie es möglich ist, auf Datenbanken mittels Java zuzugreifen. In diesem ersten Beispiel wird die Benutzeroberfläche mittels Swing gestaltet. Zur Entwicklung wurde NetBeans 3.3.1 mit dem SDK 1.4 eingesetzt. Dieses Programm ist aber auch unter SDK 1.3 lauffähig und als Datenbank Oracle 8i in der Version 8.1.6 eingesetzt. Was soll konkret Implementiert werden ? Nach dem Starten der Anwendung kommt der User in ein Anmeldefenster, in dem er sein Usernamen und sein Passwort eingibt. Diese werden in der - 51 - Datenbank auf ihre Gültigkeit überprüft. Liegt ein Fehler vor, wird eine Meldung ausgegeben und die Anwendung beendet. Wird das Passwort oder der Username nicht angegeben, wird der User darauf aufmerksam gemacht und er kann die Anmeldung vervollständigen. Ist die Anmeldung korrekt vollzogen worden, gelangt der User in das Hauptmenu, in dem er alle Tabellen der Datenbank angezeigt bekommt, auf die er zugreifen darf. Hier wählt der User eine mittels Mausklick aus und kann dann sich die Daten ansehen oder Daten eingeben oder den Tabellenaufbau ansehen. Natürlich kann hier auch die Anwendung beendet werden. Falls der User noch keine Tabelle ausgewählt hat, aber eine der Aktionen ausführen möchte, wird er darauf hingewiesen, dass er erst eine Tabelle auswählen muss. Für die einzelnen Aktionen werden dann wieder separate Fenster geöffnet, in denen dann die Aktionen ausgeführt werden. Die einzelnen Komponenten greifen dann wiederum auf die Datenbank zu, um sich die Informationen zu holen die sie benötigen. Auf was ist zu achten ? Beim Zugriff auf die Datenbank muss in der Komponente Anmeldung die URL bekannt sein, Username und Passwort werden hier eingegeben. Alle drei Parameter, URL, User und Passwort müssen dann für die Hauptauswahl zur Verfügung stehen, damit hier die Tabellen ausgelesen werden können. Für die weiteren drei Komponenten „Daten eingeben“, „Daten ansehen“, und „Tabellenaufbau ansehen“ müssen dann alle vier Parameter ( URL, User, Passwort, ausgewählte Tabelle) bekannt sein ( siehe hierzu auch Abbildung 4.5 ). - 52 - Abbildung 4.5 – Programmstruktur 4.6 Weitere Entwicklung des Tools Eine weitere Entwicklung für das Tool wäre eine zusätzliche Datenbank anzubinden. In dieser Hinsicht wurde bereits im DB-Starter ein zusätzlicher Button aufgenommen, mit dem zwischen den DBS Oracle und MySQL gewählen werden kann. Der MySQL Pfad ist noch nicht ausgebaut. Weiter wäre es möglich, dass ein View mit aufgenommen wird. Dieser View wäre z.B. für die Tabelle Fluss zu erstellen. Es würde in einem zusätzlichen Fenster ein Fluss dargestellt werden, auf dem die Messpunkte dargestellt sind. Durch Anklicken des Messpunktes könnten die Daten aufgerufen werden, die für diesen entsprechenden Messpunkt zur Verfügung stehen würden. Dieser View wäre dann natürlich sehr stark mit den entsprechenden Tabellen verknüpft und würde - 53 - nur die Möglichkeiten zeigen, welche Darstellungsmöglichkeiten mit den entsprechenden Daten prinzipiell möglich wären. Über einen weiteren Ausbau des Tools in Bezug auf Management von Benutzern und Rollen wäre nachzudenken. Dies würde zeigen, was und wie dies mit Java zu realisieren ist, für den effektiven Einsatz sei jedoch auf die Tools verwiesen, die mit Oracle ausgeliefert werden, so z.B. Enterpreis Manager Console. 4.7 Java Server Pages Eine weitere Technik mit deren Hilfe Datenbankinhalte für das Internet aufbereitet werden können soll hier kurz betrachtet werden und wird ansonsten nicht weiter verwendet. Java Server Pages (JSP) basieren auf der Servlettechnologie, sind jedoch vom Aufbau noch sehr stark an HTML angelehnt. Dies bedeutet, das dass gesamte Layout mittels HTML gestaltet wird. Diese Verbindung von Java und HTML bietet einige Vorteile die hier kurz aufgeführt werden sollen. ?? Layout durch HTML generierbar, d.h. der Layoutdesigner muss keine Java Kenntnisse besitzen. ?? Durch die Einbettung von Java in die HTML Seiten können alle nur erdenkbaren Logiken mittels Java erstellt werden, inklusive von Datenbankzugriffen mittels JDBC. ?? Zugriff auf weitere Java API’s wie z.B. RMI, JNDI, CORBA, JNDI, EJB, JMS, JTA ?? Dynamisch darzustellende Inhalte für Internetseiten. ?? Nutzung weiterer Vorteile wie z.B. Sesson Tracking. Um Java Serverpages nutzen zu können, ist es unabdingbar, dass ein Webserver eingerichtet wird. Dazu kann man beispielsweise Apache Tomcat aus dem Jakarta Projekt nutzen. Auf das Anfrage- und Antwort-Modell von http soll hier nicht weiter eingegangen werden. Dazu sei verwiesen auf entsprechende Literatur [Ber 01] und [Hal 01]. - 54 - Die Technik der JSP beruht auf der Technologie der Servlets. Dies bedeutet, dass aus den JSP Seiten beim kompilieren Servlets entstehen, die dann auf dem Server ausgeführt werden. Betrachten wir ein einfaches Servlet, das die aktuelle Uhrzeit ausgibt. Dazu ist folgender Programmtext auf dem Server abzulegen : public class TimeNow implements Servlet { public void service (ServletRequest req, ServletResponse res) throws ServletException, IOException { res.setContentType(“text/html”); PrintWriter out = res.getWriter(); out.println(“<html>”); out.println(“ <head>”); out.println(“ <title> Time Now</title>”); out.println(“ </head>”); out.println(“ <body>”); out.println(“ Es ist : “ + (new java.util.Date().toString()) ); out.println(“ </body>”); out.println(“</html>); } } Wie schon an diesem kurzen Beispiel zu erkennen ist, ist es sehr aufwendig Servlets von Hand zu programmieren, da sämtliche HTML Befehle jeweils in println-Zeilen ausgedrückt werden müssen. Wenn man nun dasselbe Beispiel als JSP programmiert, wird die Funktionalität des Javaprogramms in die HTML Seite eingebettet. Der Code der JSP Seite sieht folgendermassen aus : <html> <head> <title> Time Now </title> </head> <body> Es ist : <%= new java.util.Date().toString() %> </body> </html> Diese wenigen Codezeilen bieten dieselbe Funktionalität, wie das Servlet bzw. werden in den entsprechenden Servletcode umgewandelt. - 55 - Wie zu erkennen ist, kann das gesamte Layout der Internetseite mittels HTML gestaltet werden. Es ist natürlich auch möglich, Tabellen zu erstellen und mittels Java und einer Datenbank diese mit Informationen zu füllen. Dabei ist wiederum darauf zu achten, dass man auf die Datenbank, wie man bereits oben gesehen hat, in der festgelegten Reihenfolge zugreift. Für entsprechende Beispiele wird auf die Literatur verwiesen, so z.B. [Ber 01] S.171 ff. - 56 - ArcInfo und ArcSDE In diesem Kapitel sollen die Produkte ArcInfo und ArcSDE von Esri kurz betrachtet werden und dargestellt werden, wie diese Programme miteinander arbeiten. Über die Installation der Produkte sind entsprechende Informationen im Anhang zu finden. 5.1 ArcInfo ArcInfo setzt sich aus drei Tools zusammen. Das Haupttool stellt eine Art Explorer zur Verfügung, mit dessen Hilfe die weiteren Tools angewählt werden können. Das Haupttool ist ArcCatalog. Hier werden sämtliche Einstellungen für die weitere Arbeit getätigt. In ArcCatalog findet man auch später die Anbindung an die entsprechenden Datenbanken. Hier werden auch weitere zusätzliche Tools und Funktionalitäten eingebunden, so z.B. ArcIMS (Internet Map Server) der dann mit entsprechenden Servern zusammenarbeitet und die gewünschten Informationen aus der angebundenen Datenbank holt. Abbildung 5.1 ArcGIS Nachdem ArcCatalog gestartet wurde, zeigt sich der Explorer mit entsprechenden Wahlmöglichkeiten. Hier können dann auch die weiteren Tools gestartet werden (siehe Abbildung 5.1 und 5.2). - 57 - Abbildung 5.2 ArcCatalog Die weiteren Tools sind : ?? ArcMap Mit diesem Tool ist man in der Lage, Karten zu erstellen und verschiedene Operationen mit diesen Karten auszuführen (siehe Abbildung 5.3). Abbildung 5.3 ArcMap - 58 - ?? ArcToolbox Dieses Tool stellt einen Werkzeugkasten dar, in dem verschiedenste Funktionen abgelegt sind (siehe Abbildung 5.4). Abbildung 5.4 ArcToolbox 5.2 ArcSDE ArcSDE stellt einen Application Server dar, mit dem es möglich ist, dass die verschiedensten Produkte der Esri-Familie auf Datenbanken zugreifen können (siehe Abbildung 5.5). Abbildung 5.5 ArcSDE - 59 - Um ArcSDE richtig nutzen zu können, muss die Verbindung zur Datenbank hergestellt werden. Diese Verbindung wird in Arccatalog unter dem Menüpunkt “Database Connection“ eingerichtet. In unserem Fall wurde eine Verbindung zu einer Oracle 8i Datenbank aufgebaut. Bei korrekter Einrichtung wird die Datenbankverbindung mit entsprechend gefundenen Tabellen in ArcCatalog angezeigt (siehe Abbildung 5.6). Abbildung 5.6 Datenbankconnect - 60 - ANHANG - 61 - A 1 Literaturverzeichnis [ACA 00] Oracle 8i für Einsteiger Abbey / Corey / Abramson Verlag : Hanser ISBN : 3 – 446 – 21432 – 1 [ALG 00] Skript zur Vorlesung Algorithmen III an der FH Köln gelesen von Herrn Prof. Heiner Klocke [Bar 95] Geoinformatik – Modelle, Strukturen, Funktionen Bartelme Verlag : Springer ISBN : 3 – 540 – 65988 – 9 [Ber 01] Java Server Pages Hans Bergsten Verlag : O’Reilly ISBN : 3 – 89721 – 281 – 1 [Bil 99/1] Grundlagen der Geo-Informationssysteme Band 1 : Hardware, Software und Daten Ralf Bill Verlag : Wichmann ISBN : 3 – 87907 – 325 – 2 [Bil 99/2] Grundlagen der Geo-Informationssysteme Band 2 : Analyse, Anwendungen und neue Entwicklungen Ralf Bill Verlag : Wichmann ISBN : 3 – 87970 – 326 – 0 [BMR 98] Patternorientierte Softwarearchitektur Buschmann / Meunier / Rohnert / Sommerlad / Stal Verlag : Addison-Wesley ISBN : 3 – 8273 – 1282 – 5 [BW 01] GIS-Report 2001 Software Daten Firmen Buhmann / Wiesel Verlag : Harzer ISBN : 3 – 9803128 – 7 – 9 [DBS 00] Skript zur Vorlesung Datenbanken und Informationssysteme an der FH Köln gelesen von Frau Prof. Dr. Heide Faeskorn – Woyke - 62 - [ESK 96/1] Graphische Datenverarbeitung 1 Encarnacao / Strasser / Klein Verlag : Oldenbourg ISBN : 3 – 486 – 23223 – 1 [Hal 01] Servlets und Java Server Pages Marty Hall Verlag : Markt und Technik ISBN : 3 – 8272 – 5945 - 2 [HC 99/1] Core Java 2 Band 1 - Grundlagen Horstmann / Corell Verlag : Markt und Technik ISBN : 3 – 8272 – 9565 – 3 [HC 99/2] Core Java 2 Band 2 – Expertenwissen Horstmann / Corell Verlag : Markt und Technik ISBN : 3 – 8272 – 9566 – 1 [Loc 97] Oracle 8 Datenbankentwicklung David Lockman Verlag : Markt + Technik ISBN : 3 – 8272 – 2017 – 3 [Mas 01] MySQL in 21 Tagen Mark Maslakowski Verlag : Markt + Technik ISBN : 3 – 8272 – 5850 – 2 [MS 99] Java Programmierhandbuch und Referenz Middendorf / Singer Verlag : dpunkt ISBN : 3 – 920993 – 82 – 9 [Sed 99] Algorithmen in C++ Robert Sedgewick Verlag : Addison – Wesley ISBN : 3 – 89319 – 462 – 2 Allgemein genutzte Literatur ohne weiteren Verweiss : Computer Fachlexikon / Fachwörterbuch Ausgabe 2000 Verlag : Microsoft Press ISBN : 3 – 86063 – 822 – X - 63 - A 2 Internetseiten Allgemein http://www.gm.fh-koeln.de/ http://www.dokuwelt.de/ Java http://java.sun.com/ http://www.javabuch.de/ http://javaforum.breed.de/ http://www.javamagazin.de/ MySQL http://mmmysql.sourceforge.net/ Oracle http://www.gm.fh-koeln.de/faeskorn/ http://www.oracle.com/de/ - 64 - A 3 Verwendete Software ?? Oracle 8i Version 8.1.7 Enterpreise Edition ?? ArcInfo ?? ArcSDE 8.1 ?? Java SDK 1.4 ?? NetBeans 3.3.1 ?? ERWIN ?? TOAD - 65 - B SoftwareInstallationen Bei der Installation der Software ist auf eine feste Reihenfolge zu achten. Diese ist : 1. Oracle 8i Version 8.1.6 oder 8.1.7 2. Lizensemanager für Esri-Produkte 3. Lizensemanager konfigurieren 4. Server neu booten 5. ArcInfo Server installieren 6. Lizensemanager bestätigen 7. ArcInfo Client installieren 8. Lizensmanager bestätigen 9. ArcSDE Server installieren 9.1 anlegen des Users SDE in Oracle, Zuweisung der entsprechenden Rechte : DBA, RESORCE und CONECT 9.2 mitgeliefertes SQL Skript starten, vorher entsprechende Passwörter eintragen 9.3 ArcSDE Server installieren 10. Lizensemanager bestätigen 11. Server neu booten 12. Service von ArcSDE löschen und neu konfigurieren 13. Server neu booten Hierbei fällt auf ,dass der Lizensemanager häufig bestätigt werden muss. Dies sollte man bei der Installation konsequent durchführen, da es sonst zu enormen Problemen kommen kann. Ebenso das Booten des Servers vor und nach dem der Service von ArcSDE gelöscht und neu konfigurirt wurde. Achtung : ArcSDE 8.1 arbeitet nicht mit Oracle 9i zusammen. Dies bedeutet weiter, dass ArcSDE 8.1 nicht mit einem Pentium 4 Prozessor lauffähig ist, da Oracle 8i nicht fehlerfrei auf diesen Prozessoren arbeitet. ArcInfo ist nicht mit dem Betriessystem XP fehlerfrei zu installieren. - 66 - C DatenbankSkript C 1 SQL - Skript Flussmodell DROP TABLE Gewaesser_Fluss CASCADE CONSTRAINTS; CREATE TABLE Gewaesser_Fluss ( Gewaesser_ID INTEGER NOT NULL, Fluss_ID INTEGER NOT NULL ); ALTER TABLE Gewaesser_Fluss ADD ( PRIMARY KEY (Gewaesser_ID, Fluss_ID) ) ; DROP TABLE Telefon CASCADE CONSTRAINTS; CREATE TABLE Telefon ( Verwaltungsbehoerde_ID INTEGER NOT NULL, Stadt_ID INTEGER NULL, Durchwahl INTEGER NULL, Fax INTEGER NULL ); ALTER TABLE Telefon ADD ( PRIMARY KEY (Verwaltungsbehoerde_ID) ) ; DROP TABLE Adresse_Stadt CASCADE CONSTRAINTS; CREATE TABLE Adresse_Stadt ( Verwaltungsbehoerde_ID INTEGER NOT NULL, Stadt_ID INTEGER NOT NULL ); ALTER TABLE Adresse_Stadt ADD ( PRIMARY KEY (Verwaltungsbehoerde_ID, Stadt_ID) ) ; DROP TABLE Adresse CASCADE CONSTRAINTS; CREATE TABLE Adresse ( Verwaltungsbehoerde_ID INTEGER NOT NULL, Strasse VARCHAR2(20) NULL, Hausnummer VARCHAR2(5) NULL, PLZ INTEGER NULL, Land VARCHAR2(20) NULL ); ALTER TABLE Adresse ADD ( PRIMARY KEY (Verwaltungsbehoerde_ID) ) ; DROP TABLE Verwaltungsbehoerde CASCADE CONSTRAINTS; CREATE TABLE Verwaltungsbehoerde ( Verwaltungsbehoerde_ID INTEGER NOT NULL, Fluss_ID INTEGER NULL, Ansprechpartner VARCHAR2(20) NULL ); ALTER TABLE Verwaltungsbehoerde ADD ( PRIMARY KEY (Verwaltungsbehoerde_ID) ) ; DROP TABLE PH CASCADE CONSTRAINTS; CREATE TABLE PH ( Messwert_ID INTEGER NULL, PH_Wert FLOAT NULL ); DROP TABLE Wasserdurchfluss CASCADE CONSTRAINTS; - 67 - CREATE TABLE Wasserdurchfluss ( Messwert_ID INTEGER NULL, Qubikmeterdurchfluss FLOAT NULL ); DROP TABLE Pegelstand CASCADE CONSTRAINTS; CREATE TABLE Pegelstand ( Messwert_ID INTEGER NULL, Pegelstand_in_m FLOAT NULL ); DROP TABLE Haertegrad CASCADE CONSTRAINTS; CREATE TABLE Haertegrad ( Messwert_ID INTEGER NULL, Haertegradwert FLOAT NULL ); DROP TABLE Nitrat CASCADE CONSTRAINTS; CREATE TABLE Nitrat ( Messwert_ID INTEGER NULL, Nitrartwert FLOAT NULL ); DROP TABLE Messwert CASCADE CONSTRAINTS; CREATE TABLE Messwert ( Messwert_ID INTEGER NOT NULL, Messpunkt_ID INTEGER NOT NULL, Messzeitpunkt DATE NULL ); ALTER TABLE Messwert ADD ( PRIMARY KEY (Messwert_ID) ) ; DROP TABLE Messpunkt CASCADE CONSTRAINTS; CREATE TABLE Messpunkt ( Messpunkt_ID INTEGER NOT NULL, Fluss_ID INTEGER NOT NULL, Einrichtungszeitpunkt DATE NULL, Laengengrad VARCHAR2(20) NULL, Breitengrad VARCHAR2(20) NULL ); ALTER TABLE Messpunkt ADD ( PRIMARY KEY (Messpunkt_ID) ) ; DROP TABLE Fluss_Region CASCADE CONSTRAINTS; CREATE TABLE Fluss_Region ( Regions_ID INTEGER NOT NULL, Fluss_ID INTEGER NOT NULL ); ALTER TABLE Fluss_Region ADD ( PRIMARY KEY (Regions_ID, Fluss_ID) ) ; DROP TABLE Fluss CASCADE CONSTRAINTS; CREATE TABLE Fluss ( Fluss_ID CHAR(18) NOT NULL, Namen VARCHAR2(20) NULL, Laenge_in_km FLOAT NULL, Quellgebiet VARCHAR2(20) NULL, Muendungsgewaesser VARCHAR2(20) NULL, natuerlich CHAR(1) NULL - 68 - ); ALTER TABLE Fluss ADD ( PRIMARY KEY (Fluss_ID) ) ; DROP TABLE Viehwirtschaft CASCADE CONSTRAINTS; CREATE TABLE Viehwirtschaft ( Viehw_ID INTEGER NOT NULL, Regions_ID INTEGER NULL, Viehart VARCHAR2(20) NULL CHECK (Viehart IN ('Rinder', 'Schweine', 'Hühner')) ); ALTER TABLE Viehwirtschaft ADD ( PRIMARY KEY (Viehw_ID) ) ; DROP TABLE Agrawirtschaft CASCADE CONSTRAINTS; CREATE TABLE Agrawirtschaft ( Agrar_ID INTEGER NOT NULL, Regions_ID INTEGER NULL, Anbauflaeche_in_qkm FLOAT NULL, Anbauprodukt VARCHAR2(20) NULL CHECK (Anbauprodukt IN ('Weizen', 'Mais', 'Obst', 'Reis')), Arbeitnehmerzahl LONG NULL ); ALTER TABLE Agrawirtschaft ADD ( PRIMARY KEY (Agrar_ID) ) ; DROP TABLE Industrie CASCADE CONSTRAINTS; CREATE TABLE Industrie ( Industri_ID INTEGER NOT NULL, Regions_ID INTEGER NULL, Arbeitnehmerzahl LONG NULL, Art VARCHAR2(20) NULL CHECK (Art IN ('Auto', 'Chemische', 'Keaftwerk')) ); ALTER TABLE Industrie ADD ( PRIMARY KEY (Industri_ID) ) ; DROP TABLE Stadt CASCADE CONSTRAINTS; CREATE TABLE Stadt ( Stadt_ID INTEGER NOT NULL, Regions_ID INTEGER NULL, Einwohnerzahl LONG NULL, Stadt VARCHAR2(20) NULL, Vorwahl VARCHAR2(20) NULL ); ALTER TABLE Stadt ADD ( PRIMARY KEY (Stadt_ID) ) ; DROP TABLE Region CASCADE CONSTRAINTS; CREATE TABLE Region ( Regions_ID INTEGER NOT NULL, Bezeichnung VARCHAR2(20) NULL, Flaeche_in_qkm FLOAT NULL ); ALTER TABLE Region - 69 - ADD ( PRIMARY KEY (Regions_ID) ) ; DROP TABLE Gewaesser CASCADE CONSTRAINTS; CREATE TABLE Gewaesser ( Gewaesser_ID INTEGER NOT NULL, Tiefe_in_m FLOAT NULL, Flaeche_in_qkm FLOAT NULL, Name VARCHAR2(20) NULL ); ALTER TABLE Gewaesser ADD ( PRIMARY KEY (Gewaesser_ID) ) ; ALTER TABLE Gewaesser_Fluss ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; ALTER TABLE Gewaesser_Fluss ADD ( FOREIGN KEY (Gewaesser_ID) REFERENCES Gewaesser ) ; ALTER TABLE Telefon ADD ( FOREIGN KEY (Verwaltungsbehoerde_ID, Stadt_ID) REFERENCES Adresse_Stadt ) ; ALTER TABLE Telefon ADD ( FOREIGN KEY (Verwaltungsbehoerde_ID) REFERENCES Verwaltungsbehoerde ) ; ALTER TABLE Adresse_Stadt ADD ( FOREIGN KEY (Stadt_ID) REFERENCES Stadt ) ; ALTER TABLE Adresse_Stadt ADD ( FOREIGN KEY (Verwaltungsbehoerde_ID) REFERENCES Adresse ) ; ALTER TABLE Adresse ADD ( FOREIGN KEY (Verwaltungsbehoerde_ID) REFERENCES Verwaltungsbehoerde ) ; ALTER TABLE Verwaltungsbehoerde ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; ALTER TABLE PH ADD ( FOREIGN KEY (Messwert_ID) REFERENCES Messwert ) ; ALTER TABLE Wasserdurchfluss ADD ( FOREIGN KEY (Messwert_ID) REFERENCES Messwert ) ; ALTER TABLE Pegelstand ADD ( FOREIGN KEY (Messwert_ID) REFERENCES Messwert ) ; ALTER TABLE Haertegrad ADD ( FOREIGN KEY (Messwert_ID) REFERENCES Messwert ) ; ALTER TABLE Nitrat ADD ( FOREIGN KEY (Messwert_ID) REFERENCES Messwert ) ; ALTER TABLE Messwert ADD ( FOREIGN KEY (Messpunkt_ID) REFERENCES Messpunkt ) ; - 70 - ALTER TABLE Messpunkt ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; ALTER TABLE Fluss_Region ADD ( FOREIGN KEY (Regions_ID) REFERENCES Region ) ; ALTER TABLE Fluss_Region ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; ALTER TABLE Fluss ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; ALTER TABLE Viehwirtschaft ADD ( FOREIGN KEY (Regions_ID) REFERENCES Region ) ; ALTER TABLE Agrawirtschaft ADD ( FOREIGN KEY (Regions_ID) REFERENCES Region ) ; ALTER TABLE Industrie ADD ( FOREIGN KEY (Regions_ID) REFERENCES Region ) ; ALTER TABLE Stadt ADD ( FOREIGN KEY (Regions_ID) REFERENCES Region ) ; create trigger tI_Gewaesser_Fluss after INSERT on Gewaesser_Fluss for each row -- INSERT trigger on Gewaesser_Fluss declare numrows INTEGER; begin /* Fluss R/25 Gewaesser_Fluss ON CHILD INSERT RESTRICT */ select count(*) into numrows from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20002, 'Cannot INSERT Gewaesser_Fluss because Fluss does not exist.' ); end if; /* Gewaesser R/22 Gewaesser_Fluss ON CHILD INSERT RESTRICT select count(*) into numrows from Gewaesser where /* %JoinFKPK(:%New,Gewaesser," = "," and") */ :new.Gewaesser_ID = Gewaesser.Gewaesser_ID; if ( - 71 - */ /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20002, 'Cannot INSERT Gewaesser_Fluss because Gewaesser does not exist.' ); end if; end; / create trigger tU_Gewaesser_Fluss after UPDATE on Gewaesser_Fluss for each row declare numrows INTEGER; begin /* Fluss R/25 Gewaesser_Fluss ON CHILD UPDATE RESTRICT */ select count(*) into numrows from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20007, 'Cannot UPDATE Gewaesser_Fluss because Fluss does not exist.' ); end if; /* Gewaesser R/22 Gewaesser_Fluss ON CHILD UPDATE RESTRICT */ select count(*) into numrows from Gewaesser where /* %JoinFKPK(:%New,Gewaesser," = "," and") */ :new.Gewaesser_ID = Gewaesser.Gewaesser_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20007, 'Cannot UPDATE Gewaesser_Fluss because Gewaesser does not exist.' ); end if; end; / create trigger tI_Telefon after INSERT on Telefon for each row -- INSERT trigger on Telefon declare numrows INTEGER; - 72 - begin /* Adresse_Stadt R/34 Telefon ON CHILD INSERT SET NULL */ update Telefon set /* %SetFK(Telefon,NULL) */ Telefon.Verwaltungsbehoerde_ID = NULL, Telefon.Stadt_ID = NULL where not exists ( select * from Adresse_Stadt where /* %JoinFKPK(:%New,Adresse_Stadt," = "," and") */ :new.Verwaltungsbehoerde_ID = Adresse_Stadt.Verwaltungsbehoerde_ID and :new.Stadt_ID = Adresse_Stadt.Stadt_ID ) and /* %JoinPKPK(Telefon,:%New," = "," and") */ Telefon.Verwaltungsbehoerde_ID = :new.Verwaltungsbehoerde_ID; /* Verwaltungsbehoerde R/27 Telefon ON CHILD INSERT RESTRICT */ select count(*) into numrows from Verwaltungsbehoerde where /* %JoinFKPK(:%New,Verwaltungsbehoerde," = "," and") */ :new.Verwaltungsbehoerde_ID = Verwaltungsbehoerde.Verwaltungsbehoerde_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20002, 'Cannot INSERT Telefon because Verwaltungsbehoerde does not exist.' ); end if; end; / create trigger tU_Telefon after UPDATE on Telefon for each row -- UPDATE trigger on Telefon declare numrows INTEGER; begin /* Adresse_Stadt R/34 Telefon ON CHILD UPDATE SET NULL */ update Telefon set /* %SetFK(Telefon,NULL) */ Telefon.Verwaltungsbehoerde_ID = NULL, Telefon.Stadt_ID = NULL where not exists ( select * from Adresse_Stadt where /* %JoinFKPK(:%New,Adresse_Stadt," = "," and") */ - 73 - :new.Verwaltungsbehoerde_ID = Adresse_Stadt.Verwaltungsbehoerde_ID and :new.Stadt_ID = Adresse_Stadt.Stadt_ID ) and /* %JoinPKPK(Telefon,:%New," = "," and") */ Telefon.Verwaltungsbehoerde_ID = :new.Verwaltungsbehoerde_ID; /* Verwaltungsbehoerde R/27 Telefon ON CHILD UPDATE RESTRICT */ select count(*) into numrows from Verwaltungsbehoerde where /* %JoinFKPK(:%New,Verwaltungsbehoerde," = "," and") */ :new.Verwaltungsbehoerde_ID = Verwaltungsbehoerde.Verwaltungsbehoerde_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20007, 'Cannot UPDATE Telefon because Verwaltungsbehoerde does not exist.' ); end if; end; / create trigger tD_Adresse_Stadt after DELETE on Adresse_Stadt for each row -- DELETE trigger on Adresse_Stadt declare numrows INTEGER; begin /* Adresse_Stadt R/34 Telefon ON PARENT DELETE SET NULL */ update Telefon set /* %SetFK(Telefon,NULL) */ Telefon.Verwaltungsbehoerde_ID = NULL, Telefon.Stadt_ID = NULL where /* %JoinFKPK(Telefon,:%Old," = "," and") */ Telefon.Verwaltungsbehoerde_ID = :old.Verwaltungsbehoerde_ID and Telefon.Stadt_ID = :old.Stadt_ID; end; / create trigger tI_Adresse_Stadt after INSERT on Adresse_Stadt for each row -- INSERT trigger on Adresse_Stadt declare numrows INTEGER; begin /* Stadt R/33 Adresse_Stadt ON CHILD INSERT RESTRICT */ select count(*) into numrows from Stadt where /* %JoinFKPK(:%New,Stadt," = "," and") */ :new.Stadt_ID = Stadt.Stadt_ID; if ( /* %NotnullFK(:%New," is not null and") */ - 74 - numrows = 0 ) then raise_application_error( -20002, 'Cannot INSERT Adresse_Stadt because Stadt does not exist.' ); end if; /* Adresse R/32 Adresse_Stadt ON CHILD INSERT RESTRICT */ select count(*) into numrows from Adresse where /* %JoinFKPK(:%New,Adresse," = "," and") */ :new.Verwaltungsbehoerde_ID = Adresse.Verwaltungsbehoerde_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20002, 'Cannot INSERT Adresse_Stadt because Adresse does not exist.' ); end if; end; / create trigger tU_Adresse_Stadt after UPDATE on Adresse_Stadt for each row -- UPDATE trigger on Adresse_Stadt declare numrows INTEGER; begin /* Adresse_Stadt R/34 Telefon ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Verwaltungsbehoerde_ID <> :new.Verwaltungsbehoerde_ID or :old.Stadt_ID <> :new.Stadt_ID then update Telefon set /* %SetFK(Telefon,NULL) */ Telefon.Verwaltungsbehoerde_ID = NULL, Telefon.Stadt_ID = NULL where /* %JoinFKPK(Telefon,:%Old," = ",",") */ Telefon.Verwaltungsbehoerde_ID = :old.Verwaltungsbehoerde_ID and Telefon.Stadt_ID = :old.Stadt_ID; end if; /* Stadt R/33 Adresse_Stadt ON CHILD UPDATE RESTRICT */ select count(*) into numrows from Stadt where /* %JoinFKPK(:%New,Stadt," = "," and") */ :new.Stadt_ID = Stadt.Stadt_ID; - 75 - if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20007, 'Cannot UPDATE Adresse_Stadt because Stadt does not exist.' ); end if; /* Adresse R/32 Adresse_Stadt ON CHILD UPDATE RESTRICT */ select count(*) into numrows from Adresse where /* %JoinFKPK(:%New,Adresse," = "," and") */ :new.Verwaltungsbehoerde_ID = Adresse.Verwaltungsbehoerde_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20007, 'Cannot UPDATE Adresse_Stadt because Adresse does not exist.' ); end if; end; create trigger tD_Adresse after DELETE on Adresse for each row -- DELETE trigger on Adresse declare numrows INTEGER; begin /* Adresse R/32 Adresse_Stadt ON PARENT DELETE RESTRICT */ select count(*) into numrows from Adresse_Stadt where /* %JoinFKPK(Adresse_Stadt,:%Old," = "," and") */ Adresse_Stadt.Verwaltungsbehoerde_ID = :old.Verwaltungsbehoerde_ID; if (numrows > 0) then raise_application_error( -20001, 'Cannot DELETE Adresse because Adresse_Stadt exists.' ); end if; end; create trigger tI_Adresse after INSERT on Adresse for each row -- INSERT trigger on Adresse declare numrows INTEGER; begin /* ERwin Builtin Sat Jun 29 11:17:28 2002 */ - 76 - /* Verwaltungsbehoerde R/26 Adresse ON CHILD INSERT RESTRICT */ select count(*) into numrows from Verwaltungsbehoerde where /* %JoinFKPK(:%New,Verwaltungsbehoerde," = "," and") */ :new.Verwaltungsbehoerde_ID = Verwaltungsbehoerde.Verwaltungsbehoerde_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20002, 'Cannot INSERT Adresse because Verwaltungsbehoerde does not exist.' ); end if; end; create trigger tU_Adresse after UPDATE on Adresse for each row -- UPDATE trigger on Adresse declare numrows INTEGER; begin /* Adresse R/32 Adresse_Stadt ON PARENT UPDATE RESTRICT */ if /* %JoinPKPK(:%Old,:%New," <> "," or ") */ :old.Verwaltungsbehoerde_ID <> :new.Verwaltungsbehoerde_ID then select count(*) into numrows from Adresse_Stadt where /* %JoinFKPK(Adresse_Stadt,:%Old," = "," and") */ Adresse_Stadt.Verwaltungsbehoerde_ID = :old.Verwaltungsbehoerde_ID; if (numrows > 0) then raise_application_error( -20005, 'Cannot UPDATE Adresse because Adresse_Stadt exists.' ); end if; end if; /* Verwaltungsbehoerde R/26 Adresse ON CHILD UPDATE RESTRICT */ select count(*) into numrows from Verwaltungsbehoerde where /* %JoinFKPK(:%New,Verwaltungsbehoerde," = "," and") */ :new.Verwaltungsbehoerde_ID = Verwaltungsbehoerde.Verwaltungsbehoerde_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( - 77 - -20007, 'Cannot UPDATE Adresse because Verwaltungsbehoerde does not exist.' ); end if; end; / create trigger tD_Verwaltungsbehoerde after DELETE on Verwaltungsbehoerde for each row -- DELETE trigger on Verwaltungsbehoerde declare numrows INTEGER; begin /* Verwaltungsbehoerde R/27 Telefon ON PARENT DELETE RESTRICT */ select count(*) into numrows from Telefon where /* %JoinFKPK(Telefon,:%Old," = "," and") */ Telefon.Verwaltungsbehoerde_ID=:old.Verwaltungsbehoerde_ID; if (numrows > 0) then raise_application_error( -20001, 'Cannot DELETE Verwaltungsbehoerde because Telefon exists.' ); end if; /* Verwaltungsbehoerde R/26 Adresse ON PARENT DELETE RESTRICT */ select count(*) into numrows from Adresse where /* %JoinFKPK(Adresse,:%Old," = "," and") */ Adresse.Verwaltungsbehoerde_ID = :old.Verwaltungsbehoerde_ID; if (numrows > 0) then raise_application_error( -20001, 'Cannot DELETE Verwaltungsbehoerde because Adresse exists.' ); end if; end; create trigger tI_Verwaltungsbehoerde after INSERT on Verwaltungsbehoerde for each row -- INSERT trigger on Verwaltungsbehoerde declare numrows INTEGER; begin /* Fluss R/16 Verwaltungsbehoerde ON CHILD INSERT SET NULL */ update Verwaltungsbehoerde set /* %SetFK(Verwaltungsbehoerde,NULL) */ Verwaltungsbehoerde.Fluss_ID = NULL where not exists ( select * from Fluss where - 78 - /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID ) and /* %JoinPKPK(Verwaltungsbehoerde,:%New," = "," and") */ Verwaltungsbehoerde.Verwaltungsbehoerde_ID = :new.Verwaltungsbehoerde_ID; end; create trigger tU_Verwaltungsbehoerde after UPDATE on Verwaltungsbehoerde for each row -- UPDATE trigger on Verwaltungsbehoerde declare numrows INTEGER; begin /*Verwaltungsbehoerde R/27 Telefon ON PARENT UPDATE RESTRICT */ if /* %JoinPKPK(:%Old,:%New," <> "," or ") */ :old.Verwaltungsbehoerde_ID <> :new.Verwaltungsbehoerde_ID then select count(*) into numrows from Telefon where /* %JoinFKPK(Telefon,:%Old," = "," and") */ Telefon.Verwaltungsbehoerde_ID = :old.Verwaltungsbehoerde_ID; if (numrows > 0) then raise_application_error( -20005, 'Cannot UPDATE Verwaltungsbehoerde because Telefon exists.' ); end if; end if; /*Verwaltungsbehoerde R/26 Adresse ON PARENT UPDATE RESTRICT */ if /* %JoinPKPK(:%Old,:%New," <> "," or ") */ :old.Verwaltungsbehoerde_ID <> :new.Verwaltungsbehoerde_ID then select count(*) into numrows from Adresse where /* %JoinFKPK(Adresse,:%Old," = "," and") */ Adresse.Verwaltungsbehoerde_ID = :old.Verwaltungsbehoerde_ID; if (numrows > 0) then raise_application_error( -20005, 'Cannot UPDATE Verwaltungsbehoerde because Adresse exists.' ); end if; end if; /* Fluss R/16 Verwaltungsbehoerde ON CHILD UPDATE SET NULL */ update Verwaltungsbehoerde set /* %SetFK(Verwaltungsbehoerde,NULL) */ - 79 - Verwaltungsbehoerde.Fluss_ID = NULL where not exists ( select * from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID ) and /* %JoinPKPK(Verwaltungsbehoerde,:%New," = "," and") */ Verwaltungsbehoerde.Verwaltungsbehoerde_ID = :new.Verwaltungsbehoerde_ID; end; create trigger tI_PH after INSERT on PH for each row -- INSERT trigger on PH declare numrows INTEGER; begin /* Messwert R/10 PH ON CHILD INSERT SET NULL */ update PH set /* %SetFK(PH,NULL) */ PH.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(PH,:%New," = "," and") */ ; end; create trigger tU_PH after UPDATE on PH for each row -- UPDATE trigger on PH declare numrows INTEGER; begin /* Messwert R/10 PH ON CHILD UPDATE SET NULL */ update PH set /* %SetFK(PH,NULL) */ PH.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(PH,:%New," = "," and") */ ; end; create trigger tI_Wasserdurchfluss after INSERT on Wasserdurchfluss for each row - 80 - -- INSERT trigger on Wasserdurchfluss declare numrows INTEGER; begin /* Messwert R/9 Wasserdurchfluss ON CHILD INSERT SET NULL */ update Wasserdurchfluss set /* %SetFK(Wasserdurchfluss,NULL) */ Wasserdurchfluss.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(Wasserdurchfluss,:%New," = "," and") */ ; end; create trigger tU_Wasserdurchfluss after UPDATE on Wasserdurchfluss for each row -- UPDATE trigger on Wasserdurchfluss declare numrows INTEGER; begin /* Messwert R/9 Wasserdurchfluss ON CHILD UPDATE SET NULL */ update Wasserdurchfluss set /* %SetFK(Wasserdurchfluss,NULL) */ Wasserdurchfluss.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(Wasserdurchfluss,:%New," = "," and") */ ; end; / create trigger tI_Pegelstand after INSERT on Pegelstand for each row -- INSERT trigger on Pegelstand declare numrows INTEGER; begin /* Messwert R/8 Pegelstand ON CHILD INSERT SET NULL */ update Pegelstand set /* %SetFK(Pegelstand,NULL) */ Pegelstand.Messwert_ID = NULL where not exists ( select * from Messwert where - 81 - /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(Pegelstand,:%New," = "," and") */ ; end; create trigger tU_Pegelstand after UPDATE on Pegelstand for each row -- UPDATE trigger on Pegelstand declare numrows INTEGER; begin /* Messwert R/8 Pegelstand ON CHILD UPDATE SET NULL */ update Pegelstand set /* %SetFK(Pegelstand,NULL) */ Pegelstand.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(Pegelstand,:%New," = "," and") */ ; end; create trigger tI_Haertegrad after INSERT on Haertegrad for each row -- INSERT trigger on Haertegrad declare numrows INTEGER; begin /* Messwert R/7 Haertegrad ON CHILD INSERT SET NULL */ update Haertegrad set /* %SetFK(Haertegrad,NULL) */ Haertegrad.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(Haertegrad,:%New," = "," and") */ ; end; create trigger tU_Haertegrad after UPDATE on Haertegrad for each row -- UPDATE trigger on Haertegrad declare numrows INTEGER; begin /* Messwert R/7 Haertegrad ON CHILD UPDATE SET NULL */ update Haertegrad set /* %SetFK(Haertegrad,NULL) */ - 82 - Haertegrad.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(Haertegrad,:%New," = "," and") */ ; end; create trigger tI_Nitrat after INSERT on Nitrat for each row -- INSERT trigger on Nitrat declare numrows INTEGER; begin /* Messwert R/6 Nitrat ON CHILD INSERT SET NULL */ update Nitrat set /* %SetFK(Nitrat,NULL) */ Nitrat.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(Nitrat,:%New," = "," and") */ ; end; create trigger tU_Nitrat after UPDATE on Nitrat for each row -- UPDATE trigger on Nitrat declare numrows INTEGER; begin /* ERwin Builtin Sat Jun 29 11:17:28 2002 */ /* Messwert R/6 Nitrat ON CHILD UPDATE SET NULL */ update Nitrat set /* %SetFK(Nitrat,NULL) */ Nitrat.Messwert_ID = NULL where not exists ( select * from Messwert where /* %JoinFKPK(:%New,Messwert," = "," and") */ :new.Messwert_ID = Messwert.Messwert_ID ) and /* %JoinPKPK(Nitrat,:%New," = "," and") */ ; end; create trigger tD_Messwert after DELETE on Messwert for each row -- DELETE trigger on Messwert - 83 - declare numrows INTEGER; begin /* Messwert R/10 PH ON PARENT DELETE SET NULL */ update PH set /* %SetFK(PH,NULL) */ PH.Messwert_ID = NULL where /* %JoinFKPK(PH,:%Old," = "," and") */ PH.Messwert_ID = :old.Messwert_ID; /* Messwert R/9 Wasserdurchfluss ON PARENT DELETE SET NULL */ update Wasserdurchfluss set /* %SetFK(Wasserdurchfluss,NULL) */ Wasserdurchfluss.Messwert_ID = NULL where /* %JoinFKPK(Wasserdurchfluss,:%Old," = "," and") */ Wasserdurchfluss.Messwert_ID = :old.Messwert_ID; /* Messwert R/8 Pegelstand ON PARENT DELETE SET NULL */ update Pegelstand set /* %SetFK(Pegelstand,NULL) */ Pegelstand.Messwert_ID = NULL where /* %JoinFKPK(Pegelstand,:%Old," = "," and") */ Pegelstand.Messwert_ID = :old.Messwert_ID; /* Messwert R/7 Haertegrad ON PARENT DELETE SET NULL */ update Haertegrad set /* %SetFK(Haertegrad,NULL) */ Haertegrad.Messwert_ID = NULL where /* %JoinFKPK(Haertegrad,:%Old," = "," and") */ Haertegrad.Messwert_ID = :old.Messwert_ID; /* Messwert R/6 Nitrat ON PARENT DELETE SET NULL */ update Nitrat set /* %SetFK(Nitrat,NULL) */ Nitrat.Messwert_ID = NULL where /* %JoinFKPK(Nitrat,:%Old," = "," and") */ Nitrat.Messwert_ID = :old.Messwert_ID; end; create trigger tI_Messwert after INSERT on Messwert for each row -- INSERT trigger on Messwert declare numrows INTEGER; begin /* Messpunkt R/5 Messwert ON CHILD INSERT SET NULL */ update Messwert set /* %SetFK(Messwert,NULL) */ Messwert.Messpunkt_ID = NULL - 84 - where not exists ( select * from Messpunkt where /* %JoinFKPK(:%New,Messpunkt," = "," and") */ :new.Messpunkt_ID = Messpunkt.Messpunkt_ID ) and /* %JoinPKPK(Messwert,:%New," = "," and") */ Messwert.Messwert_ID = :new.Messwert_ID; end; create trigger tU_Messwert after UPDATE on Messwert for each row -- UPDATE trigger on Messwert declare numrows INTEGER; begin /* Messwert R/10 PH ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Messwert_ID <> :new.Messwert_ID then update PH set /* %SetFK(PH,NULL) */ PH.Messwert_ID = NULL where /* %JoinFKPK(PH,:%Old," = ",",") */ PH.Messwert_ID = :old.Messwert_ID; end if; /* Messwert R/9 Wasserdurchfluss ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Messwert_ID <> :new.Messwert_ID then update Wasserdurchfluss set /* %SetFK(Wasserdurchfluss,NULL) */ Wasserdurchfluss.Messwert_ID = NULL where /* %JoinFKPK(Wasserdurchfluss,:%Old," = ",",") */ Wasserdurchfluss.Messwert_ID = :old.Messwert_ID; end if; /* Messwert R/8 Pegelstand ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Messwert_ID <> :new.Messwert_ID then update Pegelstand set /* %SetFK(Pegelstand,NULL) */ Pegelstand.Messwert_ID = NULL where /* %JoinFKPK(Pegelstand,:%Old," = ",",") */ Pegelstand.Messwert_ID = :old.Messwert_ID; - 85 - end if; /* Messwert R/7 Haertegrad ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Messwert_ID <> :new.Messwert_ID then update Haertegrad set /* %SetFK(Haertegrad,NULL) */ Haertegrad.Messwert_ID = NULL where /* %JoinFKPK(Haertegrad,:%Old," = ",",") */ Haertegrad.Messwert_ID = :old.Messwert_ID; end if; /* Messwert R/6 Nitrat ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Messwert_ID <> :new.Messwert_ID then update Nitrat set /* %SetFK(Nitrat,NULL) */ Nitrat.Messwert_ID = NULL where /* %JoinFKPK(Nitrat,:%Old," = ",",") */ Nitrat.Messwert_ID = :old.Messwert_ID; end if; /* Messpunkt R/5 Messwert ON CHILD UPDATE SET NULL */ update Messwert set /* %SetFK(Messwert,NULL) */ Messwert.Messpunkt_ID = NULL where not exists ( select * from Messpunkt where /* %JoinFKPK(:%New,Messpunkt," = "," and") */ :new.Messpunkt_ID = Messpunkt.Messpunkt_ID ) and /* %JoinPKPK(Messwert,:%New," = "," and") */ Messwert.Messwert_ID = :new.Messwert_ID; end; create trigger tD_Messpunkt after DELETE on Messpunkt for each row -- DELETE trigger on Messpunkt declare numrows INTEGER; begin /* Messpunkt R/5 Messwert ON PARENT DELETE SET NULL */ update Messwert set /* %SetFK(Messwert,NULL) */ Messwert.Messpunkt_ID = NULL where - 86 - /* %JoinFKPK(Messwert,:%Old," = "," and") */ Messwert.Messpunkt_ID = :old.Messpunkt_ID; end; create trigger tI_Messpunkt after INSERT on Messpunkt for each row -- INSERT trigger on Messpunkt declare numrows INTEGER; begin /* Fluss R/4 Messpunkt ON CHILD INSERT SET NULL */ update Messpunkt set /* %SetFK(Messpunkt,NULL) */ Messpunkt.Fluss_ID = NULL where not exists ( select * from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID ) and /* %JoinPKPK(Messpunkt,:%New," = "," and") */ Messpunkt.Messpunkt_ID = :new.Messpunkt_ID; end; create trigger tU_Messpunkt after UPDATE on Messpunkt for each row -- UPDATE trigger on Messpunkt declare numrows INTEGER; begin /* Messpunkt R/5 Messwert ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Messpunkt_ID <> :new.Messpunkt_ID then update Messwert set /* %SetFK(Messwert,NULL) */ Messwert.Messpunkt_ID = NULL where /* %JoinFKPK(Messwert,:%Old," = ",",") */ Messwert.Messpunkt_ID = :old.Messpunkt_ID; end if; /* Fluss R/4 Messpunkt ON CHILD UPDATE SET NULL */ update Messpunkt set /* %SetFK(Messpunkt,NULL) */ Messpunkt.Fluss_ID = NULL where not exists ( select * from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID ) and /* %JoinPKPK(Messpunkt,:%New," = "," and") */ - 87 - Messpunkt.Messpunkt_ID = :new.Messpunkt_ID; end; create trigger tI_Fluss_Region after INSERT on Fluss_Region for each row -- INSERT trigger on Fluss_Region declare numrows INTEGER; begin /* Region R/3 Fluss_Region ON CHILD INSERT RESTRICT */ select count(*) into numrows from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20002, 'Cannot INSERT Fluss_Region because Region does not exist.' ); end if; /* Fluss R/2 Fluss_Region ON CHILD INSERT RESTRICT */ select count(*) into numrows from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20002, 'Cannot INSERT Fluss_Region because Fluss does not exist.' ); end if; end; create trigger tU_Fluss_Region after UPDATE on Fluss_Region for each row -- UPDATE trigger on Fluss_Region declare numrows INTEGER; begin /* Region R/3 Fluss_Region ON CHILD UPDATE RESTRICT */ select count(*) into numrows from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 - 88 - ) then raise_application_error( -20007, 'Cannot UPDATE Fluss_Region because Region does not exist.' ); end if; /* Fluss R/2 Fluss_Region ON CHILD UPDATE RESTRICT */ select count(*) into numrows from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID; if ( /* %NotnullFK(:%New," is not null and") */ numrows = 0 ) then raise_application_error( -20007, 'Cannot UPDATE Fluss_Region because Fluss does not exist.' ); end if; end; create trigger tD_Fluss after DELETE on Fluss for each row -- DELETE trigger on Fluss declare numrows INTEGER; begin /* ERwin Builtin Sat Jun 29 11:17:29 2002 */ /* Fluss R/25 Gewaesser_Fluss ON PARENT DELETE RESTRICT */ select count(*) into numrows from Gewaesser_Fluss where /* %JoinFKPK(Gewaesser_Fluss,:%Old," = "," and") */ Gewaesser_Fluss.Fluss_ID = :old.Fluss_ID; if (numrows > 0) then raise_application_error( -20001, 'Cannot DELETE Fluss because Gewaesser_Fluss exists.' ); end if; /* Fluss R/17 Fluss ON PARENT DELETE SET NULL */ update Fluss set /* %SetFK(Fluss,NULL) */ Fluss.Fluss_ID = NULL where /* %JoinFKPK(Fluss,:%Old," = "," and") */ Fluss.Fluss_ID = :old.Fluss_ID; /* Fluss R/16 Verwaltungsbehoerde ON PARENT DELETE SET NULL */ update Verwaltungsbehoerde - 89 - set /* %SetFK(Verwaltungsbehoerde,NULL) */ Verwaltungsbehoerde.Fluss_ID = NULL where /* %JoinFKPK(Verwaltungsbehoerde,:%Old," = "," and") */ Verwaltungsbehoerde.Fluss_ID = :old.Fluss_ID; /* Fluss R/4 Messpunkt ON PARENT DELETE SET NULL */ update Messpunkt set /* %SetFK(Messpunkt,NULL) */ Messpunkt.Fluss_ID = NULL where /* %JoinFKPK(Messpunkt,:%Old," = "," and") */ Messpunkt.Fluss_ID = :old.Fluss_ID; /* Fluss R/2 Fluss_Region ON PARENT DELETE RESTRICT */ select count(*) into numrows from Fluss_Region where /* %JoinFKPK(Fluss_Region,:%Old," = "," and") */ Fluss_Region.Fluss_ID = :old.Fluss_ID; if (numrows > 0) then raise_application_error( -20001, 'Cannot DELETE Fluss because Fluss_Region exists.' ); end if; end; create trigger tI_Fluss after INSERT on Fluss for each row -- INSERT trigger on Fluss declare numrows INTEGER; begin /* Fluss R/17 Fluss ON CHILD INSERT SET NULL */ update Fluss set /* %SetFK(Fluss,NULL) */ Fluss.Fluss_ID = NULL where not exists ( select * from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID ) and /* %JoinPKPK(Fluss,:%New," = "," and") */ Fluss.Fluss_ID = :new.Fluss_ID; end; create trigger tU_Fluss after UPDATE on Fluss for each row -- UPDATE trigger on Fluss declare numrows INTEGER; begin /* Fluss R/25 Gewaesser_Fluss ON PARENT UPDATE RESTRICT */ - 90 - if /* %JoinPKPK(:%Old,:%New," <> "," or ") */ :old.Fluss_ID <> :new.Fluss_ID then select count(*) into numrows from Gewaesser_Fluss where /* %JoinFKPK(Gewaesser_Fluss,:%Old," = "," and") */ Gewaesser_Fluss.Fluss_ID = :old.Fluss_ID; if (numrows > 0) then raise_application_error( -20005, 'Cannot UPDATE Fluss because Gewaesser_Fluss exists.' ); end if; end if; /* Fluss R/17 Fluss ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Fluss_ID <> :new.Fluss_ID then update Fluss set /* %SetFK(Fluss,NULL) */ Fluss.Fluss_ID = NULL where /* %JoinFKPK(Fluss,:%Old," = ",",") */ Fluss.Fluss_ID = :old.Fluss_ID; end if; /* Fluss R/16 Verwaltungsbehoerde ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Fluss_ID <> :new.Fluss_ID then update Verwaltungsbehoerde set /* %SetFK(Verwaltungsbehoerde,NULL) */ Verwaltungsbehoerde.Fluss_ID = NULL where /* %JoinFKPK(Verwaltungsbehoerde,:%Old," = ",",") */ Verwaltungsbehoerde.Fluss_ID = :old.Fluss_ID; end if; /* Fluss R/4 Messpunkt ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Fluss_ID <> :new.Fluss_ID then update Messpunkt set /* %SetFK(Messpunkt,NULL) */ Messpunkt.Fluss_ID = NULL - 91 - where /* %JoinFKPK(Messpunkt,:%Old," = ",",") */ Messpunkt.Fluss_ID = :old.Fluss_ID; end if; /* Fluss R/2 Fluss_Region ON PARENT UPDATE RESTRICT */ if /* %JoinPKPK(:%Old,:%New," <> "," or ") */ :old.Fluss_ID <> :new.Fluss_ID then select count(*) into numrows from Fluss_Region where /* %JoinFKPK(Fluss_Region,:%Old," = "," and") */ Fluss_Region.Fluss_ID = :old.Fluss_ID; if (numrows > 0) then raise_application_error( -20005, 'Cannot UPDATE Fluss because Fluss_Region exists.' ); end if; end if; /* Fluss R/17 Fluss ON CHILD UPDATE SET NULL */ update Fluss set /* %SetFK(Fluss,NULL) */ Fluss.Fluss_ID = NULL where not exists ( select * from Fluss where /* %JoinFKPK(:%New,Fluss," = "," and") */ :new.Fluss_ID = Fluss.Fluss_ID ) and /* %JoinPKPK(Fluss,:%New," = "," and") */ Fluss.Fluss_ID = :new.Fluss_ID; end; create trigger tI_Viehwirtschaft after INSERT on Viehwirtschaft for each row -- INSERT trigger on Viehwirtschaft declare numrows INTEGER; begin /* Region R/14 Viehwirtschaft ON CHILD INSERT SET NULL */ update Viehwirtschaft set /* %SetFK(Viehwirtschaft,NULL) */ Viehwirtschaft.Regions_ID = NULL where not exists ( select * from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID - 92 - ) and /* %JoinPKPK(Viehwirtschaft,:%New," = "," and") */ Viehwirtschaft.Viehw_ID = :new.Viehw_ID; end; create trigger tU_Viehwirtschaft after UPDATE on Viehwirtschaft for each row -- UPDATE trigger on Viehwirtschaft declare numrows INTEGER; begin /* Region R/14 Viehwirtschaft ON CHILD UPDATE SET NULL */ update Viehwirtschaft set /* %SetFK(Viehwirtschaft,NULL) */ Viehwirtschaft.Regions_ID = NULL where not exists ( select * from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID ) and /* %JoinPKPK(Viehwirtschaft,:%New," = "," and") */ Viehwirtschaft.Viehw_ID = :new.Viehw_ID; end; create trigger tI_Agrawirtschaft after INSERT on Agrawirtschaft for each row -- INSERT trigger on Agrawirtschaft declare numrows INTEGER; begin /* Region R/13 Agrawirtschaft ON CHILD INSERT SET NULL */ update Agrawirtschaft set /* %SetFK(Agrawirtschaft,NULL) */ Agrawirtschaft.Regions_ID = NULL where not exists ( select * from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID ) and /* %JoinPKPK(Agrawirtschaft,:%New," = "," and") */ Agrawirtschaft.Agrar_ID = :new.Agrar_ID; end; create trigger tU_Agrawirtschaft after UPDATE on Agrawirtschaft for each row -- UPDATE trigger on Agrawirtschaft declare numrows INTEGER; begin /* Region R/13 Agrawirtschaft ON CHILD UPDATE SET NULL */ update Agrawirtschaft set /* %SetFK(Agrawirtschaft,NULL) */ Agrawirtschaft.Regions_ID = NULL where - 93 - not exists ( select * from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID ) and /* %JoinPKPK(Agrawirtschaft,:%New," = "," and") */ Agrawirtschaft.Agrar_ID = :new.Agrar_ID; end; create trigger tI_Industrie after INSERT on Industrie for each row -- INSERT trigger on Industrie declare numrows INTEGER; begin /* Region R/12 Industrie ON CHILD INSERT SET NULL */ update Industrie set /* %SetFK(Industrie,NULL) */ Industrie.Regions_ID = NULL where not exists ( select * from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID ) and /* %JoinPKPK(Industrie,:%New," = "," and") */ Industrie.Industri_ID = :new.Industri_ID; end; create trigger tU_Industrie after UPDATE on Industrie for each row -- UPDATE trigger on Industrie declare numrows INTEGER; begin /* Region R/12 Industrie ON CHILD UPDATE SET NULL */ update Industrie set /* %SetFK(Industrie,NULL) */ Industrie.Regions_ID = NULL where not exists ( select * from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID ) and /* %JoinPKPK(Industrie,:%New," = "," and") */ Industrie.Industri_ID = :new.Industri_ID; end; create trigger tD_Stadt after DELETE on Stadt for each row -- DELETE trigger on Stadt declare numrows INTEGER; begin /* Stadt R/33 Adresse_Stadt ON PARENT DELETE RESTRICT */ - 94 - select count(*) into numrows from Adresse_Stadt where /* %JoinFKPK(Adresse_Stadt,:%Old," = "," and") */ Adresse_Stadt.Stadt_ID = :old.Stadt_ID; if (numrows > 0) then raise_application_error( -20001, 'Cannot DELETE Stadt because Adresse_Stadt exists.' ); end if; end; create trigger tI_Stadt after INSERT on Stadt for each row -- INSERT trigger on Stadt declare numrows INTEGER; begin /* Region R/11 Stadt ON CHILD INSERT SET NULL */ update Stadt set /* %SetFK(Stadt,NULL) */ Stadt.Regions_ID = NULL where not exists ( select * from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID ) and /* %JoinPKPK(Stadt,:%New," = "," and") */ Stadt.Stadt_ID = :new.Stadt_ID; end; create trigger tU_Stadt after UPDATE on Stadt for each row -- UPDATE trigger on Stadt declare numrows INTEGER; begin /* Stadt R/33 Adresse_Stadt ON PARENT UPDATE RESTRICT */ if /* %JoinPKPK(:%Old,:%New," <> "," or ") */ :old.Stadt_ID <> :new.Stadt_ID then select count(*) into numrows from Adresse_Stadt where /* %JoinFKPK(Adresse_Stadt,:%Old," = "," and") */ Adresse_Stadt.Stadt_ID = :old.Stadt_ID; if (numrows > 0) then raise_application_error( -20005, 'Cannot UPDATE Stadt because Adresse_Stadt exists.' ); - 95 - end if; end if; /* Region R/11 Stadt ON CHILD UPDATE SET NULL */ update Stadt set /* %SetFK(Stadt,NULL) */ Stadt.Regions_ID = NULL where not exists ( select * from Region where /* %JoinFKPK(:%New,Region," = "," and") */ :new.Regions_ID = Region.Regions_ID ) and /* %JoinPKPK(Stadt,:%New," = "," and") */ Stadt.Stadt_ID = :new.Stadt_ID; end; create trigger tD_Region after DELETE on Region for each row -- DELETE trigger on Region declare numrows INTEGER; begin /* Region R/14 Viehwirtschaft ON PARENT DELETE SET NULL */ update Viehwirtschaft set /* %SetFK(Viehwirtschaft,NULL) */ Viehwirtschaft.Regions_ID = NULL where /* %JoinFKPK(Viehwirtschaft,:%Old," = "," and") */ Viehwirtschaft.Regions_ID = :old.Regions_ID; /* Region R/13 Agrawirtschaft ON PARENT DELETE SET NULL */ update Agrawirtschaft set /* %SetFK(Agrawirtschaft,NULL) */ Agrawirtschaft.Regions_ID = NULL where /* %JoinFKPK(Agrawirtschaft,:%Old," = "," and") */ Agrawirtschaft.Regions_ID = :old.Regions_ID; /* Region R/12 Industrie ON PARENT DELETE SET NULL */ update Industrie set /* %SetFK(Industrie,NULL) */ Industrie.Regions_ID = NULL where /* %JoinFKPK(Industrie,:%Old," = "," and") */ Industrie.Regions_ID = :old.Regions_ID; /* Region R/11 Stadt ON PARENT DELETE SET NULL */ update Stadt set /* %SetFK(Stadt,NULL) */ Stadt.Regions_ID = NULL where /* %JoinFKPK(Stadt,:%Old," = "," and") */ - 96 - Stadt.Regions_ID = :old.Regions_ID; /* Region R/3 Fluss_Region ON PARENT DELETE RESTRICT */ select count(*) into numrows from Fluss_Region where /* %JoinFKPK(Fluss_Region,:%Old," = "," and") */ Fluss_Region.Regions_ID = :old.Regions_ID; if (numrows > 0) then raise_application_error( -20001, 'Cannot DELETE Region because Fluss_Region exists.' ); end if; end; create trigger tU_Region after UPDATE on Region for each row -- UPDATE trigger on Region declare numrows INTEGER; begin /* Region R/14 Viehwirtschaft ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Regions_ID <> :new.Regions_ID then update Viehwirtschaft set /* %SetFK(Viehwirtschaft,NULL) */ Viehwirtschaft.Regions_ID = NULL where /* %JoinFKPK(Viehwirtschaft,:%Old," = ",",") */ Viehwirtschaft.Regions_ID = :old.Regions_ID; end if; /* Region R/13 Agrawirtschaft ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Regions_ID <> :new.Regions_ID then update Agrawirtschaft set /* %SetFK(Agrawirtschaft,NULL) */ Agrawirtschaft.Regions_ID = NULL where /* %JoinFKPK(Agrawirtschaft,:%Old," = ",",") */ Agrawirtschaft.Regions_ID = :old.Regions_ID; end if; /* Region R/12 Industrie ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Regions_ID <> :new.Regions_ID then update Industrie set - 97 - /* %SetFK(Industrie,NULL) */ Industrie.Regions_ID = NULL where /* %JoinFKPK(Industrie,:%Old," = ",",") */ Industrie.Regions_ID = :old.Regions_ID; end if; /* Region R/11 Stadt ON PARENT UPDATE SET NULL */ if /* %JoinPKPK(:%Old,:%New," <> "," or " */ :old.Regions_ID <> :new.Regions_ID then update Stadt set /* %SetFK(Stadt,NULL) */ Stadt.Regions_ID = NULL where /* %JoinFKPK(Stadt,:%Old," = ",",") */ Stadt.Regions_ID = :old.Regions_ID; end if; /* Region R/3 Fluss_Region ON PARENT UPDATE RESTRICT */ if /* %JoinPKPK(:%Old,:%New," <> "," or ") */ :old.Regions_ID <> :new.Regions_ID then select count(*) into numrows from Fluss_Region where /* %JoinFKPK(Fluss_Region,:%Old," = "," and") */ Fluss_Region.Regions_ID = :old.Regions_ID; if (numrows > 0) then raise_application_error( -20005, 'Cannot UPDATE Region because Fluss_Region exists.' ); end if; end if; end; create trigger tD_Gewaesser after DELETE on Gewaesser for each row -- DELETE trigger on Gewaesser declare numrows INTEGER; begin /* Gewaesser R/22 Gewaesser_Fluss ON PARENT DELETE RESTRICT */ select count(*) into numrows from Gewaesser_Fluss where /* %JoinFKPK(Gewaesser_Fluss,:%Old," = "," and") */ Gewaesser_Fluss.Gewaesser_ID = :old.Gewaesser_ID; if (numrows > 0) then raise_application_error( -20001, - 98 - 'Cannot DELETE Gewaesser because Gewaesser_Fluss exists.' ); end if; end; create trigger tU_Gewaesser after UPDATE on Gewaesser for each row -- UPDATE trigger on Gewaesser declare numrows INTEGER; begin /* Gewaesser R/22 Gewaesser_Fluss ON PARENT UPDATE RESTRICT */ if /* %JoinPKPK(:%Old,:%New," <> "," or ") */ :old.Gewaesser_ID <> :new.Gewaesser_ID then select count(*) into numrows from Gewaesser_Fluss where /* %JoinFKPK(Gewaesser_Fluss,:%Old," = "," and") */ Gewaesser_Fluss.Gewaesser_ID = :old.Gewaesser_ID; if (numrows > 0) then raise_application_error( -20005, 'Cannot UPDATE Gewaesser because Gewaesser_Fluss exists.' ); end if; end if; end; / - 99 - C 2 SQL - Skript kleines Flussmodell DROP TABLE Lage_am_Fluss CASCADE CONSTRAINTS; CREATE TABLE Lage_am_Fluss ( Region_ID INTEGER NOT NULL, Name VARCHAR2(30) NOT NULL, Fluss_ID INTEGER NOT NULL, Flusskm NUMBER NULL ); ALTER TABLE Lage_am_Fluss ADD ( PRIMARY KEY (Region_ID, Name, Fluss_ID) ) ; DROP TABLE Messwert CASCADE CONSTRAINTS; CREATE TABLE Messwert ( Messwert_ID INTEGER NOT NULL, Messpunkt_ID INTEGER NULL, Messzeitpunkt VARCHAR2(20) NULL, Pegelstand_in_m FLOAT NULL ); ALTER TABLE Messwert ADD ( PRIMARY KEY (Messwert_ID) ) ; DROP TABLE Messpunkt CASCADE CONSTRAINTS; CREATE TABLE Messpunkt ( Messpunkt_ID INTEGER NOT NULL, Fluss_ID INTEGER NULL, Laengengrad VARCHAR2(10) NULL, Breitengrad VARCHAR2(10) NULL, Einrichtungszeitpunk DATE NULL ); ALTER TABLE Messpunkt ADD ( PRIMARY KEY (Messpunkt_ID) ) ; DROP TABLE Fluss_Region CASCADE CONSTRAINTS; CREATE TABLE Fluss_Region ( Region_ID INTEGER NOT NULL, Fluss_ID INTEGER NOT NULL, Name VARCHAR2(30) NULL ); DROP TABLE Fluss CASCADE CONSTRAINTS; CREATE TABLE Fluss ( Fluss_ID INTEGER NOT NULL, Name VARCHAR2(20) NULL, Laenge_in_km FLOAT NULL, Quellgebiet VARCHAR2(30) NULL, Muendungsgewaesser VARCHAR2(20) NULL ); ALTER TABLE Fluss ADD ( PRIMARY KEY (Fluss_ID) ) ; DROP TABLE Region CASCADE CONSTRAINTS; CREATE TABLE Region ( Region_ID INTEGER NOT NULL, - 100 - Name VARCHAR2(30) NOT NULL, Kategorie VARCHAR2(20) NULL CHECK (Kategorie IN ('Ort', 'Industrie', 'Agrawirtschaft', 'Viehwirtschaft')), Flaeche_in_qkm FLOAT NULL ); ALTER TABLE Region ADD ( PRIMARY KEY (Region_ID, Name) ) ; ALTER TABLE Lage_am_Fluss ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; ALTER TABLE Lage_am_Fluss ADD ( FOREIGN KEY (Region_ID, Name) REFERENCES Region ) ; ALTER TABLE Messwert ADD ( FOREIGN KEY (Messpunkt_ID) REFERENCES Messpunkt ) ; ALTER TABLE Messpunkt ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; ALTER TABLE Fluss_Region ADD ( FOREIGN KEY (Region_ID, Name) REFERENCES Region ) ; ALTER TABLE Fluss_Region ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; ALTER TABLE Fluss ADD ( FOREIGN KEY (Fluss_ID) REFERENCES Fluss ) ; - 101 - C 3 SQL - Skript Daten für kleines Flussmodell Insert into Fluss (Fluss_ID, Name, Laenge_in_km, Quellgebiet, Muendungsgewaesser) values(1, 'Rhein', 1250, 'Schweiz', 'Nordsee'); Insert into Fluss Fluss (Fluss_ID, Name, Laenge_in_km, Quellgebiet, Muendungsgewaesser) values(2, 'Mosel', 250, 'Deutschland', 'Rhein'); Insert into Fluss Fluss (Fluss_ID, Name, Laenge_in_km, Quellgebiet, Muendungsgewaesser) values(3, 'Donau', 2500, '', 'Schwarzemeer'); Insert into Region (Region_ID, Name, Kategorie, Flaeche_in_qkm) values(1, 'Köln', 'Ort', 67); Insert into Region (Region_ID, Name, Kategorie, Flaeche_in_qkm) values(2, 'Bonn', 'Ort', 50); Insert into Region (Region_ID, Name, Kategorie, Flaeche_in_qkm) values(3, 'Wien', 'Ort', 72); Insert into Fluss_Region (Region_ID, Fluss_ID) values (1, 1); Insert into Fluss_Region (Region_ID, Fluss_ID) values (2, 1); Insert into Fluss_Region (Region_ID, Fluss_ID) values (3, 3); Insert into Messpunkt (Messpunkt_ID, Fluss_ID, Laengengrad, Breitengrad, EINRICHTUNGSZEITPUNK) values (1, 1, '3°O', '4°W', '12.12.2001'); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (1, 1, '12.12.01 13.00', 4.10); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (2, 1, '12.12.01 13.10', 4.11); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (3, 1, '12.12.01 13.20', 4.12); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (4, 1, '12.12.01 13.30', 4.13); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (5, 1, '12.12.01 13.40', 4.14); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (6, 1, '12.12.01 13.50', 4.14); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (7, 1, '12.12.01 14.00', 4.13); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (8, 1, '12.12.01 14.10', 4.12); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (9, 1, '12.12.01 14.20', 4.11); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (10, 1, '12.12.01 14.30', 4.10); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (11, 1, '12.12.01 14.40', 4.09); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (12, 1, '12.12.01 14.50', 4.08); Insert into Messwert (Messwert_ID, Messpunkt_ID, Messzeitpunkt, Pegelstand_in_m) values (13, 1, '12.12.01 15.00', 4.07); - 102 - D Programmcode Das Programm wurde mit NetBeans 3.3.1 entwickelt, entsprechend werden spezielle API’s von Netbeans verwendet. Deweiteren muss das jar-File Class12.jar, zu finden bei Oracle, in den Pfad aufgenommen werden, damit die Datenbankanbindung einwandfrei funktioniert. Außerdem+ muss die URL der Datenbank angepasst werden. D 1 dbt_Starter.java /* * dbt_Starter.java * * DataBankTool V0.02 (11.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 11. April 2002, 10:34 */ package de.ducesoft.rsz.diparbeit; /** * dbt-Starter ist der Starter fuer das DataBankTool. * Hier kann ausgewaehlt werden auf welches DBSytem * Oracle oder MySql zugegriffen werden soll. * * @author Reinhard S. Zöllner */ public class dbt_Starter extends javax.swing.JFrame { /** Creates new form DBT_Starter */ public dbt_Starter() { super("DataBankTool V0.02"); // durch super werden Methoden der // Elternklasse geerbt, hier insbesondere // das bezeichnen der Fenster. initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jLabel2 = new javax.swing.JLabel(); - 103 - jPanel1 = new javax.swing.JPanel(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); jLabel1 = new javax.swing.JLabel(); jButton3 = new javax.swing.JButton(); jLabel3 = new javax.swing.JLabel(); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jLabel2.setVerticalAlignment(javax.swing.SwingConstants.TOP); jLabel2.setText("DataBankTool V0.02"); jLabel2.setToolTipText("Version von DBT"); jLabel2.setFont(new java.awt.Font("Arial", 1, 18)); getContentPane().add(jLabel2, java.awt.BorderLayout.NORTH); jPanel1.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); jButton1.setToolTipText("W\u00e4hlt Oracle als DBS aus"); jButton1.setText("Oracle 8i DBS"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton1ActionPerformed(evt); } }); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { oraAuswahl(evt); } }); jPanel1.add(jButton1, new org.netbeans.lib.awtextra.AbsoluteConstraints(100, 80, 170, 40)); jButton2.setToolTipText("w\u00e4hlt MySQL als DBS aus"); jButton2.setText("MySQL DBS"); jButton2.setMaximumSize(new java.awt.Dimension(112, 26)); jButton2.setMinimumSize(new java.awt.Dimension(112, 26)); jButton2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton2ActionPerformed(evt); } }); jButton2.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { mySQLAusgewaehlt(evt); } - 104 - }); jPanel1.add(jButton2, new org.netbeans.lib.awtextra.AbsoluteConstraints(100, 130, 170, 40)); jLabel1.setText("W\u00e4hlen Sie auf welches DB-System zugegriffen werden soll."); jPanel1.add(jLabel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 40, -1, -1)); jButton3.setToolTipText("Zeigt eine Information an"); jButton3.setText("Informationen \u00fcber DBT"); jButton3.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { info(evt); } }); jPanel1.add(jButton3, new org.netbeans.lib.awtextra.AbsoluteConstraints(100, 180, 170, 40)); getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER); jLabel3.setText("(c) R.S.Z\u00f6llner, DuceSoft 2k2"); jLabel3.setToolTipText("(c)"); getContentPane().add(jLabel3, java.awt.BorderLayout.SOUTH); pack(); }//GEN-END:initComponents private void info(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_info // Es ist moeglich mittels IE HTML-Seiten anzuzeigen, dazu werden diese // mittels Runtime.getRuntime().exec(....); aufgerufen. siehe hier. // Nachteil : der Pfad ist nicht dynamisch. try { Runtime.getRuntime().exec("c:\\Programme\\internet explorer\\iexplore.exe c:\\dbt\\dbt.html"); } catch (Exception ex) { System.out.println("Fehler : " + ex ); } }//GEN-LAST:event_info private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed // Add your handling code here: }//GEN-LAST:event_jButton1ActionPerformed private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed // Add your handling code here: }//GEN-LAST:event_jButton2ActionPerformed - 105 - private void mySQLAusgewaehlt(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_mySQLAusgewaehlt // Derzeit noch nicht implementiert // Sorgt dann fuer die ANbindung von MySQL-DBS }//GEN-LAST:event_mySQLAusgewaehlt private void oraAuswahl(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_oraAuswahl // zum aufraeumen, bzw. der besseren Uebersicht Fenster schliessen sf.setVisible(false); // Nachfolgendes Fenster aufrufen new anmeldung().show(); }//GEN-LAST:event_oraAuswahl /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_exitForm System.exit(0); }//GEN-LAST:event_exitForm /** * @param args the command line arguments */ public static void main(String args[]) { // setVisible() wird deswegen genutzt um das fenster zu schliessen // wenn es nicht mehr benoetigt wird. // Desweiteren ist show() deprecated ! sf = new dbt_Starter(); sf.setVisible(true); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton3; private javax.swing.JButton jButton2; private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel1; private javax.swing.JPanel jPanel1; // End of variables declaration//GEN-END:variables // Variable die fuer eigenen Code benoetigt werden private static dbt_Starter sf; // sf = Start Fenster // Ende der Variablen decclaration } - 106 - D 2 anmeldung.java /* * anmeldung.java * * DataBankTool V0.02 (11.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 26. Februar 2002, 16:41 */ package de.ducesoft.rsz.diparbeit; import java.sql.*; import java.io.*; /** * In dieser Komponente wird sichergestelt das die Anmeldung * an das DBS korrekt ausgefuehrt wird. * * @author Reinhard Zoellner */ public class anmeldung extends javax.swing.JFrame { /** Creates new form anmeldung */ public anmeldung() { super("DataBankTool V0.02"); initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jLabel1 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jTextField1 = new javax.swing.JTextField(); jPasswordField1 = new javax.swing.JPasswordField(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } - 107 - }); jLabel1.setText("Datenbankanmeldung"); jLabel1.setFont(new java.awt.Font("Dialog", 1, 18)); getContentPane().add(jLabel1,new org.eans.lib.awtextra.AbsoluteConstraints(90, 30, 220, 30)); jButton1.setText("anmelden"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { verbinden(evt); } }); getContentPane().add(jButton1,new org.netbeans.lib.awtextra.AbsoluteConstraints(160, 220, -1, -1)); jLabel2.setText("Benutzer"); getContentPane().add(jLabel2,new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 110, -1, -1)); jLabel3.setText("Passwort"); getContentPane().add(jLabel3,new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 140, -1, -1)); getContentPane().add(jTextField1,new org.netbeans.lib.awtextra.AbsoluteConstraints(160, 110, 90, -1)); getContentPane().add(jPasswordField1,new org.netbeans.lib.awtextra.AbsoluteConstraints(160, 140, 90, -1)); pack(); }//GEN-END:initComponents private void verbinden(java.awt.event.MouseEvent evt) {//GENFIRST:event_verbinden // Add your handling code here: String user = jTextField1.getText().trim(); String passwd = jPasswordField1.getText().trim(); oraZugriffsDaten.setMyURL("jdbc:oracle:thin:@localhost:1521:rsz"); // 2481 Connection v_connection = null; Statement v_statement= null; Integer v_int; try { // Oracle JDBC Treiber laden bzw. den DriverManager bekannt machen Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (java.lang.ClassNotFoundException e) { System.err.println("Class Not Found Exception : " + e.getMessage()); } - 108 - try { v_connection = DriverManager.getConnection (oraZugriffsDaten.getMyURL(), user, passwd); v_statement = v_connection.createStatement(); v_statement.close(); v_connection.close(); } catch(SQLException e) { String fehler = e.getMessage(); System.out.println(fehler); System.out.println(fehler.substring(6,35)); if(fehler.substring(0,9).equals("ORA-01017")) { new fpofu(new javax.swing.JFrame(), true).show(); System.exit(0); } if(fehler.substring(6,35).equals("Benutzer- oder Kennwortangabe")){ new fpfu(new javax.swing.JFrame(), true).show(); err = 1; } } if (err == 0) { oraZugriffsDaten.setMyUser(user); oraZugriffsDaten.setMyPasswd(passwd); new hauptmenu().show(); } else { err = 0; } }//GEN-LAST:event_verbinden /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm System.exit(0); }//GEN-LAST:event_exitForm // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPasswordField jPasswordField1; private javax.swing.JTextField jTextField1; private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables private int err = 0; } - 109 - D 3 oraZugriffsDaten.java /* * oraZugriffsDaten.java * * DataBankTool V0.02 (11.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 11. April 2002, 17:19 */ package de.ducesoft.rsz.diparbeit; /** * Verwaltet die Zugriffsdaten fuer die Datenbankzugriffe. * D.h. Es werden wenn bekann ist gespeichert : * - Username * - Password * - SID * - URL * - zu nutzende Tabelle * * @author Reinhard S. Zöllner */ public class oraZugriffsDaten { /** Creates a new instance of OraZugiffsDaten */ public oraZugriffsDaten() { myurl = null; myuser = null; mypasswd = null; mysid = null; mytabelle = null; } protected static void setMyURL(String url) { myurl = url; } protected static void setMyUser(String user) { myuser = user; } protected static void setMyPasswd(String passwd) { mypasswd = passwd; } protected static void setMyTabelle(String tabelle) { - 110 - mytabelle = tabelle; } protected static String getMyURL() { return myurl; } protected static String getMyUser() { return myuser; } protected static String getMyPasswd() { return mypasswd; } protected static String getMyTabelle() { return mytabelle; } protected static void setMySID(String sid) { mysid = sid; } protected static String getMySID() { return mysid; } private static String myurl; private static String myuser; private static String mypasswd; private static String mytabelle; private static String mysid; } - 111 - D 4 hauptmenu.java /* * hauptmenu.java * * DataBankTool V0.02 (11.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 28. Februar 2002, 14:55 */ package de.ducesoft.rsz.diparbeit; import java.util.*; import java.sql.*; import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; /** * Stellt die Hauptauswahl dar. Man kann waehlen zwischen * Daten eingeben, ansehen und Beenden. * * @author Reinhard Zoellner */ public class hauptmenu extends javax.swing.JFrame implements ListSelectionListener { /** Creates new form hauptmenu */ public hauptmenu() { super("DataBankTool V0.02"); initComponents(); } private void ansehen(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_ansehen String tabelle = oraZugriffsDaten.getMyTabelle(); if(tabelle == null) { err = 1; new eta(new javax.swing.JFrame(), true).show(); } if ( err == 0) { // Tabell ist korrekt ausgewaehlt // Aufruf gewuenschten Daten zum ansehen. new lookData().show(); } - 112 - }//GEN-LAST:event_ansehen private void aendern(java.awt.event.MouseEvent evt) { String tabelle = oraZugriffsDaten.getMyTabelle(); if(tabelle == null) { err = 1; new eta(new javax.swing.JFrame(), true).show(); } if ( err == 0) { // Tabell ist korrekt ausgewaehlt // Aufruf den Aufbau der gewuenschten Tabelle ansehen. new changeData().show(); } } private void aufbauansehen(java.awt.event.MouseEvent evt) { String tabelle = oraZugriffsDaten.getMyTabelle(); if(tabelle == null) { err = 1; new eta(new javax.swing.JFrame(), true).show(); } if ( err == 0) { // Tabell ist korrekt ausgewaehlt // Aufruf den Aufbau der gewuenschten Tabelle ansehen. new taa().show(); } } private void eingeben(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_eingeben String tabelle = oraZugriffsDaten.getMyTabelle(); // int err = 0; if(tabelle == null) { err = 1; new eta(new javax.swing.JFrame(), true).show(); } if ( err == 0) { // Tabell ist korrekt ausgewaehlt new editData().show(); } }//GEN-LAST:event_eingeben private void ende(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_ende System.exit(0); }//GEN-LAST:event_ende /* * url := korekte url zum einloggen in ein DBS * user := ueberpruefter User fuer ein DBS * passwd := Passwort fuer den User */ private void initComponents() { - 113 - jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); jButton3 = new javax.swing.JButton(); jButton4 = new javax.swing.JButton(); jButton5 = new javax.swing.JButton(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jLabel1.setText("Sie sind eingelogt als :"); getContentPane().add(jLabel1,new org.netbeans.lib.awtextra.AbsoluteConstraints(10, 10, -1, -1)); jLabel2.setText(oraZugriffsDaten.getMyUser()); getContentPane().add(jLabel2,new org.netbeans.lib.awtextra.AbsoluteConstraints(150, 10, -1, -1)); jLabel3.setText("Es existieren volgende Tabellen :"); getContentPane().add(jLabel3,new org.netbeans.lib.awtextra.AbsoluteConstraints(10, 60, -1, -1)); jButton1.setText("Daten eingeben"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { eingeben(evt); } }); getContentPane().add(jButton1,new org.netbeans.lib.awtextra.AbsoluteConstraints(270, 130, -1, -1)); jButton5.setText("Daten aendern"); jButton5.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { aendern(evt); } }); getContentPane().add(jButton5,new org.netbeans.lib.awtextra.AbsoluteConstraints(270, 90, -1, -1)); jButton2.setText("Daten ansehen"); jButton2.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { ansehen(evt); - 114 - } }); getContentPane().add(jButton2,new org.netbeans.lib.awtextra.AbsoluteConstraints(270, 170, -1, -1)); jButton4.setText("Tabellenaufbau ansehen"); jButton4.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { aufbauansehen(evt); } }); getContentPane().add(jButton4,new org.netbeans.lib.awtextra.AbsoluteConstraints(270, 210, -1, -1)); jButton3.setText("Beenden"); jButton3.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { ende(evt); } }); getContentPane().add(jButton3,new org.netbeans.lib.awtextra.AbsoluteConstraints(270, 250, -1, -1)); Vector wordVector = new Vector(); Connection v_connection = null; Statement v_statement= null; try { // Oracle JDBC Treiber laden bzw. den DriverManager bekannt machen Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (java.lang.ClassNotFoundException e) { System.err.println("Class Not Found Exception : " + e.getMessage()); } try { v_connection = DriverManager.getConnection( oraZugriffsDaten.getMyURL(), oraZugriffsDaten.getMyUser(), oraZugriffsDaten.getMyPasswd()); v_statement = v_connection.createStatement(); ResultSet v_resultset = v_statement.executeQuery( "Select Table_Name from USER_TABLES"); while (v_resultset.next()) { String s1 = v_resultset.getString(1); wordVector.add(s1); } v_statement.close(); v_connection.close(); } catch(SQLException e) { } - 115 - jList1 = new javax.swing.JList(wordVector); JScrollPane scrollPane = new JScrollPane(jList1); JPanel p = new JPanel(); p.add(scrollPane); jList1.addListSelectionListener(this); getContentPane().add(p,new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 130, -1, -1)); pack(); } /* * valueChanged-Methode aufgrund von ListSelectionListener * Interface implementieren. */ public void valueChanged(ListSelectionEvent evt) { JList source = (JList)evt.getSource(); Object[] values = source.getSelectedValues(); String text = ""; for (int i = 0; i < values.length; i++) { String word = (String)values[i]; text += word + " "; } // Tabelle ist ausgewaehlt somit err auf 0 setzen. oraZugriffsDaten.setMyTabelle(text); err = 0; } /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_exitForm System.exit(0); }//GEN-LAST:event_exitForm // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton3; private javax.swing.JButton jButton2; private javax.swing.JButton jButton1; private javax.swing.JList jList1; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables private javax.swing.JButton jButton4; private javax.swing.JButton jButton5; private String ausgewaehlteTabelle = null; private int err = 1; // Fehlervariable erst Tabelle auswaehlen } - 116 - D 5 changeData.java /* * changeData.java * * DataBankTool V0.02 (11.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 11. April 2002, 12:40 */ package de.ducesoft.rsz.diparbeit; /** * * @author Reinhard S. Zöllner */ public class changeData extends javax.swing.JFrame { /** Creates new form changeData */ public changeData() { super("DataBankTool V0.02"); initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jLabel1 = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); jTable1 = new javax.swing.JTable(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jLabel1.setText( "W\u00e4hlen sie den Datensatz aus der ge\u00e4ndert werden soll."); getContentPane().add(jLabel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 30, -1, -1)); - 117 - jTable1.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {null, null, null, null}, {null, null, null, null}, {null, null, null, null}, {null, null, null, null} }, new String [] { "Title 1", "Title 2", "Title 3", "Title 4" } )); jScrollPane1.setViewportView(jTable1); getContentPane().add(jScrollPane1, new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 80, -1, -1)); pack(); }//GEN-END:initComponents /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_exitForm System.exit(0); }//GEN-LAST:event_exitForm /** * @param args the command line arguments */ public static void main(String args[]) { new changeData().show(); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTable jTable1; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables } - 118 - D 6 druck.java /* * druck.java * * DataBankTool V0.01 (5.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 6. März 2002, 10:38 */ package de.ducesoft.rsz.diparbeit; /** * * @author Reinhard Zoellner */ public class druck extends javax.swing.JFrame { /** Creates new form druck */ public druck() { super("DataBankTool V0.01"); initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jLabel1 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jLabel1.setText("Hier k\u00f6nnte eine Druck-.Methode implementiert werden."); getContentPane().add(jLabel1,new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 10, 330, 40)); - 119 - jButton1.setText("zur\u00fcck"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { zurueck(evt); } }); getContentPane().add(jButton1,new org.netbeans.lib.awtextra.AbsoluteConstraints(150, 50, -1, -1)); pack(); }//GEN-END:initComponents private void zurueck(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_zurueck setVisible(false); dispose(); }//GEN-LAST:event_zurueck /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_exitForm System.exit(0); }//GEN-LAST:event_exitForm // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables } - 120 - D 7 editData.java /* * editData.java * * DataBankTool V0.02 (13.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 6. März 2002, 14:39 */ package de.ducesoft.rsz.diparbeit; import java.util.*; import java.sql.*; import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; /** * Daten in der entsprechenden Tabelle eingeben. * * @author Reinhard Zoellner */ public class editData extends javax.swing.JFrame { /** Creates new form editData */ public editData() { super("DataBankTool V0.02"); initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); jScrollPane1 = new javax.swing.JScrollPane(); jPanel21 = new javax.swing.JPanel(); - 121 - getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jLabel1.setText("Hier k\u00f6nnen Daten s\u00e4tze in die Tabelle aufgenommen werden."); getContentPane().add(jLabel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 30, -1, -1)); jLabel2.setText("Derzeit ist folgende Tabelle ge\u00f6ffnet :"); getContentPane().add(jLabel2, new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 50, -1, -1)); jLabel3.setText(oraZugriffsDaten.getMyTabelle()); getContentPane().add(jLabel3, new org.netbeans.lib.awtextra.AbsoluteConstraints(250, 50, -1, -1)); jButton1.setText("Daten \u00fcbernehmen"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent evt) { uebernehmen(evt); } }); getContentPane().add(jButton1, new org.netbeans.lib.awtextra.AbsoluteConstraints(90, 270, -1, -1)); jButton2.setText("zur\u00fcck"); jButton2.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { zurueck(evt); } }); getContentPane().add(jButton2, new org.netbeans.lib.awtextra.AbsoluteConstraints(250, 270, -1, -1)); jPanel21.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); Connection v_connection = null; Statement v_statement= null; try { // Oracle JDBC Treiber laden bzw. den DriverManager bekannt machen Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (java.lang.ClassNotFoundException e) { - 122 - System.err.println("Class Not Found Exception : " + e.getMessage()); } try { v_connection = DriverManager.getConnection(oraZugriffsDaten.getMyURL(), oraZugriffsDaten.getMyUser(), oraZugriffsDaten.getMyPasswd()); v_statement = v_connection.createStatement(); ResultSet v_resultset = v_statement.executeQuery("Select * from " + oraZugriffsDaten.getMyTabelle()); ResultSetMetaData rsmd = v_resultset.getMetaData(); int numberOfColumns = rsmd.getColumnCount(); setMyNumberOfColumns(numberOfColumns); for (int i = 1; i <= numberOfColumns; i++) { JLabel bezeichner = new JLabel(); String name = rsmd.getColumnName(i); bezeichner.setText(name); System.out.println(name); jPanel21.add(bezeichner, new org.netbeans.lib.awtextra.AbsoluteConstraints(10,i*20-20, -1, -1)); } v_statement.close(); v_connection.close(); } catch(SQLException e) { } //Leeren Textfelder erzeugen zur Dateneingabe eintrag = new JTextField[getMyNumberOfColumns()+1]; for (int i = 1; i <= getMyNumberOfColumns(); i++) { eintrag[i] = new JTextField(); jPanel21.add(eintrag[i] , new org.netbeans.lib.awtextra.AbsoluteConstraints(175,i*20-20, 100, -1)); } jScrollPane1.setViewportView(jPanel21); getContentPane().add(jScrollPane1, new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 100, 280, 130)); pack(); }//GEN-END:initComponents private void zurueck(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_zurueck setVisible(false); dispose(); - 123 - }//GEN-LAST:event_zurueck private void uebernehmen(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_uebernehmen Vector wordVector = new Vector(); Connection v_connection = null; Statement v_statement= null; String[] datentypen = new String[getMyNumberOfColumns()+1]; String[] datenName = new String[getMyNumberOfColumns()+1]; try { // Oracle JDBC Treiber laden bzw. den DriverManager bekannt machen Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (java.lang.ClassNotFoundException e) { System.err.println("Class Not Found Exception : " + e.getMessage()); } try { v_connection = DriverManager.getConnection( oraZugriffsDaten.getMyURL(), oraZugriffsDaten.getMyUser(), oraZugriffsDaten.getMyPasswd()); v_statement = v_connection.createStatement(); ResultSet v_resultset = v_statement.executeQuery("Select * from " + oraZugriffsDaten.getMyTabelle()); ResultSetMetaData rsmd = v_resultset.getMetaData(); int numberOfColumns = rsmd.getColumnCount(); for (int i = 1; i <= getMyNumberOfColumns()+1 ; i ++) { datentypen[i] = rsmd.getColumnTypeName(i); datenName[i] = rsmd.getColumnName(i); } v_statement.close(); v_connection.close(); } catch(SQLException e) { } String valueString = ""; String dataString = ""; for (int i = 1; i <= getMyNumberOfColumns(); i++) { if( ! eintrag[i].getText().equals("")) { // ggf. mit entsprechen den weiteren Datentypen erweitern. if (datentypen[i].equals("VARCHAR2")) { valueString = valueString + "'" + eintrag[i].getText() + "'"; } else { - 124 - valueString = valueString + eintrag[i].getText(); } dataString = dataString + datenName[i]; // Bis auf an den letzten ein Komma anhaengen if(i != getMyNumberOfColumns()) { valueString = valueString + ","; dataString = dataString + " ,"; } // ValuesString und DataString sind zusammengesetzt. } } // ueberpruefen ob letztes Zeichen ein Komma dann loeschen if(valueString.endsWith(",")) { valueString = valueString.substring(0,valueString.length()-1); } if(dataString.endsWith(",")) { dataString = dataString.substring(0,dataString.length()-1); } try { v_connection = DriverManager.getConnection( oraZugriffsDaten.getMyURL(), oraZugriffsDaten.getMyUser(), oraZugriffsDaten.getMyPasswd()); v_statement = v_connection.createStatement(); v_statement.executeUpdate("INSERT INTO " + oraZugriffsDaten.getMyTabelle() + "(" + dataString + ") VALUES (" + valueString + ")"); v_statement.close(); v_connection.close(); } catch(SQLException e) { System.out.println(e); } System.out.println(valueString); System.out.println(dataString); }//GEN-LAST:event_uebernehmen /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_exitForm System.exit(0); }//GEN-LAST:event_exitForm - 125 - private void setMyNumberOfColumns(int number) { myNumberOfColumns = number; } private int getMyNumberOfColumns() { return myNumberOfColumns; } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton2; private javax.swing.JButton jButton1; private javax.swing.JPanel jPanel21; private javax.swing.JLabel jLabel3; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables private int myNumberOfColumns = 0; private JTextField[] eintrag; } - 126 - D 8 eta.java /* * eta.java * * DataBankTool V0.01 (5.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 1. März 2002, 10:36 */ package de.ducesoft.rsz.diparbeit; /** * Dialogfenster : Erst Tabelle auswaehlen. * * @author Reinhard Zoellner */ public class eta extends javax.swing.JDialog { /** Creates new form eta */ public eta(java.awt.Frame parent, boolean modal) { super(parent, modal); initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jLabel1 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { closeDialog(evt); } }); jLabel1.setText("Bitte erst eine Tabelle ausw\u00e4hlen !"); jLabel1.setFont(new java.awt.Font("Dialog", 1, 14)); getContentPane().add(jLabel1,new org.netbeans.lib.awtextra.AbsoluteConstraints(50, 10, 290, 40)); - 127 - jButton1.setText("Zur\u00fcck"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mousePressed(java.awt.event.MouseEvent evt) { zurueck(evt); } }); getContentPane().add(jButton1,new org.netbeans.lib.awtextra.AbsoluteConstraints(150, 70, -1, -1)); pack(); }//GEN-END:initComponents private void zurueck(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_zurueck setVisible(false); dispose(); }//GEN-LAST:event_zurueck /** Closes the dialog */ private void closeDialog(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_closeDialog setVisible(false); dispose(); }//GEN-LAST:event_closeDialog // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables } - 128 - D 9 fpfu.java /* * fpfu.java * * DataBankTool V0.01 (5.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 28. Februar 2002, 11:24 */ package de.ducesoft.rsz.diparbeit; /** * Dialogfenster das angezeigt wird wenn das Passwort oder * der Username oder beides fehlt. * * @author Reinhard Zoellner */ public class fpfu extends javax.swing.JDialog { /** Creates new form fpfu */ public fpfu(java.awt.Frame parent, boolean modal) { super(parent, modal); initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jLabel1 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { closeDialog(evt); } }); jLabel1.setText("Fehlender Username oder fehlendes Passwort"); jLabel1.setFont(new java.awt.Font("Dialog", 1, 14)); getContentPane().add(jLabel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 20, 350, 50)); - 129 - jButton1.setText("Zur\u00fcck"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { zurueck(evt); } }); getContentPane().add(jButton1, new org.netbeans.lib.awtextra.AbsoluteConstraints(160, 70, -1, -1)); pack(); }//GEN-END:initComponents private void zurueck(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_zurueck setVisible(false); dispose(); }//GEN-LAST:event_zurueck /** Closes the dialog */ private void closeDialog(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_closeDialog setVisible(false); dispose(); }//GEN-LAST:event_closeDialog // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables } - 130 - D 10 fpofu.java /* * fpofu.java * * DataBankTool V0.01 (5.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 27. Februar 2002, 11:56 */ package de.ducesoft.rsz.diparbeit; /** * Dialogfenster das angezeigt wird wenn ein falsches * Passwort oder ein falscher Username eingegeben wurde. * * @author Reinhard Zoellner */ public class fpofu extends javax.swing.JDialog { /** Creates new form fpofu */ public fpofu(java.awt.Frame parent, boolean modal) { super(parent, modal); initComponents(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jLabel1 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { closeDialog(evt); } }); jLabel1.setText("Falscher Username oder Falsches Passwort"); jLabel1.setFont(new java.awt.Font("Dialog", 1, 14)); getContentPane().add(jLabel1,new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 0, 320, 100)); - 131 - jButton1.setText("Beenden"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { ende(evt); } }); getContentPane().add(jButton1,new org.netbeans.lib.awtextra.AbsoluteConstraints(160, 80, -1, -1)); pack(); }//GEN-END:initComponents private void ende(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_ende System.exit(0); }//GEN-LAST:event_ende /** Closes the dialog */ private void closeDialog(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_closeDialog setVisible(false); dispose(); }//GEN-LAST:event_closeDialog // Variables declaration - do not modify //GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables } - 132 - D 11 lookData.java /* * lookData.java * * DataBankTool V0.02 (13.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 4. März 2002, 12:26 */ package de.ducesoft.rsz.diparbeit; import java.util.*; import java.sql.*; import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; /** * Die Datensaetze einer Tabelle anzeigen. * * @author Reinhard Zoellner */ public class lookData extends javax.swing.JFrame implements ListSelectionListener { /** Creates new form lookData */ public lookData() { super("DataBankTool V0.02"); initComponents(); } private void initComponents() { jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); jList1 = new javax.swing.JList(); jLabel4 = new javax.swing.JLabel(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); addWindowListener(new java.awt.event.WindowAdapter() { - 133 - public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jLabel1.setText("In der Tabelle : "); getContentPane().add(jLabel1,new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 30, -1, -1)); jLabel2.setText("sind volgende Eintr\u00e4ge enthalten."); getContentPane().add(jLabel2,new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 60, -1, -1)); jLabel3.setText("hier könnte eine Tabellenüberschrift stehen"); getContentPane().add(jLabel3,new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 100, 380, -1)); jButton1.setText("zur\u00fcck"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { zurueck(evt); } }); getContentPane().add(jButton1,new org.netbeans.lib.awtextra.AbsoluteConstraints(70, 380, -1, -1)); jButton2.setText("drucken"); jButton2.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { drucken(evt); } }); getContentPane().add(jButton2,new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 380, -1, -1)); Vector wordVector = new Vector(); Connection v_connection = null; Statement v_statement= null; try { // Oracle JDBC Treiber laden bzw. den DriverManager bekannt machen Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (java.lang.ClassNotFoundException e) { System.err.println("Class Not Found Exception : " + e.getMessage()); } try { v_connection = DriverManager.getConnection( oraZugriffsDaten.getMyURL(), - 134 - oraZugriffsDaten.getMyUser(), oraZugriffsDaten.getMyPasswd()); v_statement = v_connection.createStatement(); ResultSet v_resultset = v_statement.executeQuery( "Select * from "+ oraZugriffsDaten.getMyTabelle()); ResultSetMetaData rsmd = v_resultset.getMetaData(); setNumberOfColumns(rsmd.getColumnCount()); String[] elz = new String[getNumberOfColumns()+1]; // einzufuegende Leerzeichen int [] laengsterString = new int[getNumberOfColumns()+1]; for( int i = 1; i <= getNumberOfColumns(); i++) { laengsterString[i] = 0; } while (v_resultset.next()) { String[] s = new String[getNumberOfColumns()+1]; for (int i = 1; i <= getNumberOfColumns(); i++) { s[i]= v_resultset.getString(i); } for (int i= 1; i<= getNumberOfColumns(); i++) { s1 = s1 + " " + s[i] ; } wordVector.add(s1); } v_statement.close(); v_connection.close(); } catch(SQLException e) { } jList1 = new javax.swing.JList(wordVector); JScrollPane scrollPane = new JScrollPane(jList1); JPanel p = new JPanel(); p.add(scrollPane); jList1.addListSelectionListener(this); getContentPane().add(p,new org.netbeans.lib.awtextra.AbsoluteConstraints(30, 130, -1, -1)); jLabel4.setText(oraZugriffsDaten.getMyTabelle()); getContentPane().add(jLabel4,new org.netbeans.lib.awtextra.AbsoluteConstraints(120, 30, -1, -1)); pack(); } private void drucken(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_drucken new druck().show(); }//GEN-LAST:event_drucken - 135 - private void zurueck(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_zurueck setVisible(false); dispose(); }//GEN-LAST:event_zurueck /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_exitForm System.exit(0); }//GEN-LAST:event_exitForm /* * valueChanged-Methode aufgrund von ListSelectionListener * Interface implementieren. */ public void valueChanged(ListSelectionEvent evt) { JList source = (JList)evt.getSource(); Object[] values = source.getSelectedValues(); String text = ""; for (int i = 0; i < values.length; i++) { String word = (String)values[i]; text += word + " "; } } private void setNumberOfColumns(int columns) { numberOfColumns = columns; } private int getNumberOfColumns() { return numberOfColumns; } private void setTabellenueberschrift (String s) { tabellenueberschrift = s; } private String getTabellenueberschrift () { return tabellenueberschrift; } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton2; private javax.swing.JButton jButton1; private javax.swing.JList jList1; private javax.swing.JLabel jLabel4; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables private int numberOfColumns = 0; - 136 - private String tabellenueberschrift = null; } - 137 - D 12 taa.java /* * taa.java * * DataBankTool V0.02 (13.4.2k2) * * (c) Reinhard S. Zoellner * erstellt im Rahmen der Diplomarbeit * * Created on 1. März 2002, 19:41 */ package de.ducesoft.rsz.diparbeit; import java.util.*; import java.sql.*; import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; /** * taa := Tabellenaufbau ansehen * * @author Reinhard Zoellner */ public class taa extends javax.swing.JFrame implements ListSelectionListener { /** Creates new form taa */ public taa() { super("DataBankTool V0.02"); initComponents(); } /* * tabelle := Tabellenbezeichnung der angezeigten Tabelle. */ private void initComponents() { jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); jList1 = new javax.swing.JList(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); - 138 - addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); jLabel1.setText("Tabellneaufbau von "); jLabel1.setFont(new java.awt.Font("Dialog", 1, 14)); getContentPane().add(jLabel1,new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 20, 150, 30)); jLabel2.setText(oraZugriffsDaten.getMyTabelle()); jLabel2.setFont(new java.awt.Font("Dialog", 1, 14)); getContentPane().add(jLabel2,new org.netbeans.lib.awtextra.AbsoluteConstraints(190, 20, 150, 30)); jLabel3.setText("ansehen."); jLabel3.setFont(new java.awt.Font("Dialog", 1, 14)); getContentPane().add(jLabel3,new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 50, 70, 30)); jLabel4.setText(" Zeil Type Casesensitiv besreibbar"); jLabel4.setFont(new java.awt.Font("Lucida Sans Typewriter", 0, 12)); getContentPane().add(jLabel4,new org.netbeans.lib.awtextra.AbsoluteConstraints(50, 130, 400, 30)); jList1.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0))); jList1.setMinimumSize(new java.awt.Dimension(200, 100)); Vector wordVector = new Vector(); Connection v_connection = null; Statement v_statement= null; try { // Oracle JDBC Treiber laden bzw. den DriverManager bekannt machen Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (java.lang.ClassNotFoundException e) { System.err.println("Class Not Found Exception : " + e.getMessage()); } try { v_connection = DriverManager.getConnection( oraZugriffsDaten.getMyURL(), oraZugriffsDaten.getMyUser(), oraZugriffsDaten.getMyPasswd()); v_statement = v_connection.createStatement(); ResultSet v_resultset = v_statement.executeQuery( "Select * from " + oraZugriffsDaten.getMyTabelle()); - 139 - ResultSetMetaData rsmd = v_resultset.getMetaData(); int numberOfColumns = rsmd.getColumnCount(); int laengsterString = 0; String colName = null; // Leerzeichen zum formatieren der Tabelle String leerzeichen = null; String zusl = " "; String tofl = " "; for (int i = 1 ; i <= numberOfColumns; i++) { colName = rsmd.getColumnName(i); int j = colName.length(); if ( j > laengsterString ) { laengsterString = j; } } for (int i = 1 ; i <= numberOfColumns; i++) { colName = rsmd.getColumnName(i); int j = colName.length(); String dbtype = rsmd.getColumnTypeName(i); boolean caseSen = rsmd.isCaseSensitive(i); boolean writable = rsmd.isWritable(i); leerzeichen = " "; // Formatierung der Tabelle implements Fenster mittels Leezeichen // 1. verschiedene Column-Laengen auf gleiche laenge bringen for (int k = j; k < laengsterString; k++) { leerzeichen = leerzeichen + " "; } // 2. Bei verschiedenen Datentypen entstehen entsprechend mehr // oder weniger Leerzeichen if( dbtype.equals("VARCHAR2")) { zusl = " "; } if( dbtype.equals("NUMBER")) { zusl = " "; } if( dbtype.equals("DATE")) { zusl = " "; } if( dbtype.equals("BLOB")) { zusl = " "; } if( dbtype.equals("CLOB")) { zusl = " "; } if( dbtype.equals("CHAR")) { zusl = " "; } if( dbtype.equals("LONG")) { - 140 - zusl = " "; } // 3. wenn caseSensitiv true bzw. false ist muessen entsprechend // die Leerzeichen eingesetzt werden. if( caseSen == true ) { tofl = " "; } // Den String fuer die Ausgabe zusammensetzen. String vectoreintrag = colName + leerzeichen + dbtype + zusl + caseSen + tofl + writable; // Den String in den Vektor uernehmen. wordVector.add(vectoreintrag); } v_statement.close(); v_connection.close(); } catch(SQLException e) { } jList1 = new javax.swing.JList(wordVector); JScrollPane scrollPane = new JScrollPane(jList1); JPanel p = new JPanel(); jList1.setFont(new java.awt.Font("Lucida Sans Typewriter", 0, 12)); p.add(scrollPane); jList1.addListSelectionListener(this); getContentPane().add(p,new org.netbeans.lib.awtextra.AbsoluteConstraints(50, 150, -1, -1)); jButton1.setText("Zur\u00fcck"); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { zurueck(evt); } }); getContentPane().add(jButton1,new org.netbeans.lib.awtextra.AbsoluteConstraints(60, 90, -1, -1)); jButton2.setText("Drucken"); jButton2.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { drucken(evt); } }); getContentPane().add(jButton2,new org.netbeans.lib.awtextra.AbsoluteConstraints(210, 90, -1, -1)); - 141 - pack(); } /* * valueChanged-Methode aufgrund von ListSelectionListener * Interface implementieren. */ public void valueChanged(ListSelectionEvent evt) { JList source = (JList)evt.getSource(); Object[] values = source.getSelectedValues(); String text = ""; for (int i = 0; i < values.length; i++) { String word = (String)values[i]; text += word + " "; } } private void drucken(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_drucken new druck().show(); }//GEN-LAST:event_drucken private void zurueck(java.awt.event.MouseEvent evt) { //GEN-FIRST:event_zurueck setVisible(false); dispose(); }//GEN-LAST:event_zurueck /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) { //GEN-FIRST:event_exitForm System.exit(0); }//GEN-LAST:event_exitForm // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton2; private javax.swing.JButton jButton1; private javax.swing.JList jList1; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel4; } - 142 - E Pflichtenheft 1. Zielbestimmungen 1.1 Mußkriterien Erstellung eines einfachen Datenmodells zur Modellierung von Wassereinzugsgebieten. Konkretisierung am BSP.: Chile. Umsetzung und Realisierung des Modells und Integration der einzelnen Komponenten, Datenbank und GIS-Produkt und Kommunikation dieser, sowie erster Testeinsatz. Beschreibung und Dokumentation des Vorgehens, Datenmodells, Implementierung, Testeinsatz und Architekturmodell. 1.2 Wunschkriterien Umsetzung von Rollen, Administrator, zwei Unteradministratoren und User. Zugriff auf Server soll über Browser erfolgen, so dass keine weitere Software auf dem Client installiert werden muß. Oracle Datenbankinstallation auf Server im Institut für Tropentechnologie, zuerst Nutzung der Oracle-Datenbank des Fachbereiches Informatik in Gummersbach. Schnittstellenumsetzung : Import und Export von Daten mittels OGC. ArcSDE / ArcIMS sollten genutzt werden. Wünschenswert wäre der Zugriff auf mehrere Datenbanken. 1.3 Abgrenzungskriterien Es ist nicht beabsichtigt, ein ausführliches Datenmodell, das alle Aspekte eines Flusseinzugsgebietes widerspiegelt zu erstellen. Replikationsprobleme werden nicht berücksichtigt. Bei Nutzung einer eigenen Datenbank wird die Administration durch das Institut für Tropentechnologie übernommen. 2. Produkteinsatz 2.1 Anwendungsbereich GIS im Wassermanagement. - 143 - 2.2 Zielgruppe Wasserexperten, Studenten, Assistenten und Professoren im Institut für Tropentechnologie. 2.3 Betriebsbedingungen Das System zur Eingabe und Manipulation von Daten soll im 24-7-365 Tage Betrieb laufen. Über Zugriffszeiten wird keine Aussage gemacht. 3. Produktumgebung 3.1 Software ?? Win 2000 ?? ArcInfo ?? ArcSDE ?? Oracle ?? TOAD ?? ERWIN ?? Ggf. SureSafe (Versionsmanagement) ?? NetBeans 3.3.1 3.2 Hardware ?? Server für ArcInfo ?? Server für Oracle und entsprechende Middleware ?? Client (Normaler PC) 3.3 Produktschnittstellen ?? Oracle ? ArcInfo ?? ArcIMS ? Browser ?? ArcSDE ? Oracle 4. Produktfunktionen Problembeschreibung Institut für Tropentechnologie. - 144 - 5. Produktdaten Siehe ggf. späteres ausführliches Daten modell. 6. Produktleistungen 7. Benutzeroberfläche Browser (mit entsprechenden Eingabemasken) / ESRI 8. Qualitätsbestimmungen 9. Globale Testfälle In der ersten Umsetzung fiktive Daten. 10. Entwicklungsumgebung ?? NetBeans 3.3.1 11. Ergänzungen Eigentlich geht es darum festzustellen, welche Möglichkeiten wie genutzt werden können, so dass im späteren Projekt dann entschieden werden kann, welche Umsetzung realisiert werden soll. - 145 - Notizen - 146 - Erklärung Ich versichere, die von mir vorgelegte Arbeit selbständig verfasst zu haben. Alle Stellen, die wörtlich oder sinngemäß aus veröffentlichten oder nicht veröffentlichten Arbeiten anderer entnommen sind, habe ich als entnommen kenntlich gemacht. Sämtliche Quellen und Hilfsmittel, die ich für die Arbeit benutzt habe, sind angegenben. Die Arbeit hat mit gleichem Inhalt bzw. in wesentlichen Teilen noch keiner anderen Prüfungsbehörde vgorgelegen. Köln, den Reinhard S. Zöllner - 147 -