Web-basiertes Data

Werbung
..
..
..
..
..
Web-Publishing-Seminar WS 98/99
Web-basiertes DataWarehousing
.
.
.
.
.
.
.
.
.
.
eingereicht bei Prof. Dr. Vornberger
eingereicht von:
Dipl.-Kfm. Karsten Brodmann
Matrikel-Nr.: 806 343
Osnabrück, den 18.12.1998
Inhaltsverzeichnis
Einleitung ................................................................................................................................... 1
Motivation............................................................................................................................. 1
Ziel und Vorgehensweise ....................................................................................................... 1
Client/Server-Architekturen......................................................................................................... 2
Protokolle: TCP/IP und HTTP ............................................................................................... 2
Die TCP/IP-Protokollfamilie ............................................................................................ 2
Das HTTP-Protokoll......................................................................................................... 2
2- und 3-stufige Architekturen ............................................................................................... 2
Das World Wide Web ............................................................................................................ 4
Datenbankarchitekturen ......................................................................................................... 4
Java-Client/Server-Architekturen: Remote Methode Invocation.............................................. 5
Architektur Web-basierter Data-Warehouses ............................................................................... 6
Realisierungsalternativen ....................................................................................................... 7
Datenbankintegration mit JDBC............................................................................................. 8
JDBC-Treiber................................................................................................................... 8
JDBC-Treiber-Architekturen ............................................................................................ 9
JDBC-Treiber-Architektur mit Typ-1-Treibern............................................................ 9
JDBC-Treiber-Architektur mit Typ-2-Treibern.......................................................... 10
JDBC-Treiber-Architektur mit Typ-3-Treibern.......................................................... 11
JDBC-Treiber-Architektur mit Typ-4-Treibern.......................................................... 11
Kommunikation im Web-basierten Data-Warehouse............................................................. 12
JDBC in der Praxis.................................................................................................................... 13
Grundlagen der Verwendung von JDBC............................................................................... 13
Die Driver-Schnittstelle .................................................................................................. 13
Das DriverManager-Objekt............................................................................................. 14
Verbindung zur Datenbank: Die Connection-Schnittstelle ............................................... 15
Projekt: Abenteuer und Freizeit............................................................................................ 16
Projektbeschreibung ....................................................................................................... 16
Anwendungsarchitektur.................................................................................................. 17
Relationales Datenmodell ............................................................................................... 17
Java-Klassen-Design ...................................................................................................... 17
Bewertung des Prototypen .............................................................................................. 18
Schlußbetrachtung und Ausblick ............................................................................................... 19
Literaturverzeichnis................................................................................................................... 19
Anhang ..................................................................................................................................... 20
Hinweise zu den Programmbeispielen .................................................................................. 20
Client-/Server-Kommunikation via Sockets.......................................................................... 21
SocketServer.java........................................................................................................... 21
SocketClient.java ........................................................................................................... 21
SocketClientFrame.java.................................................................................................. 23
DlgSocketClient.java...................................................................................................... 23
DialogLayout.java .......................................................................................................... 25
Remote Method Innvocation ................................................................................................ 28
Lookup.java ................................................................................................................... 28
LookupServer.java ......................................................................................................... 28
LookupClient.java .......................................................................................................... 29
..
..
..
..
..
Web-basiertes DataWarehousing
Web-Publishing-Seminar WS 98/99
Einleitung
Motivation
Data-Warehousing nennt man einen Prozeß, bei dem Daten aus operativen Administrations- und
Dispositionssystemen extrahiert und in einer dedizierten Datenbank zur Verarbeitung durch Programme für Abfragen, Berichte, Online-Analyse (OLAP – Online Analytical Processing), Entscheidungsunterstützungssysteme und ähnlichem mehr bereitgestellt werden [vgl. KIMB96].
Die meisten Data-Warehouse-Systeme setzen traditionelle Client/Server-Techniken ein, um auf den
Warehouse-Informationsspeicher zuzugreifen. In jüngerer Zeit hat der Einsatz von Intranets zur
Verwendung von Web-Clients zum Zugriff auf den Data-Warehouse-Datenbankserver geführt.
Ein Web-basiertes Data-Warehouse-System bietet zahlreiche Vorteile. Zum Beispiel gehören zu
den Web-Schnittstellen schlanke Clients, die geringere Hardwareanforderungen als normale Desktop-Systeme stellen. Dadurch werden Hardwarekosten gesenkt, die Zuverlässigkeit erhöht und der
Aufwand für die Hardwarewartung verringert. Die Verwendung schlanker Clients ermöglicht den
Unternehmen außerdem, die Vorteile neuer Hardwaretechnologien wie Netzwerkcomputer und
Window-based-Terminals erheblich besser zu nutzen [vgl. WHIT98].
Darüber hinaus wird der größte Teil der von Web-Clients genutzten Software zentral auf Servern
gespeichert und nach Bedarf von den Clients heruntergeladen. Dieser Ansatz verringert den mit der
Installation und der Pflege der (bisherigen) Client-Software verbundene Aufwand.
Ziel und Vorgehensweise
OLAP-, MIS-Anwendungen (MIS – Management Information Systems) und ähnliche erfordern ein
hohes Maß an Interaktionsmöglichkeiten, um den an sie gestellten Anforderungen gerecht werden
zu können [vgl. THIE98]. Es ist noch nicht lange her, da waren Web-Anwendungen diesen Anforderungen nicht gewachsen, in jüngster Vergangenheit aber sprießen entsprechende Web-Clients geradezu aus dem Boden. Kaum ein Hersteller von Data-Warehouse-Frontends läßt es sich nehmen,
neben den „klassischen“ Anwendungen auch eine entsprechende Web-Variante anzubieten [vgl.
WHIT98].
Möglich wurde die o.g. Inflation durch Kompontentechnologien wie z.B. ActiveX aus dem Hause
Microsoft oder der noch jungen und „Web-fähigen“ Programmiersprache Java von Sun Microsystems, Inc. Java erregt auch heute noch, etwa drei Jahre nach Freigabe der ersten Version Ende
1995, das Interesse der Fachwelt. Java stößt ständig in neue Anwendungsgebiete vor, unter anderem auch in das Data-Warehousing.
Data-Warehouse-Anwendungen benötigen Datenbankanbindungen. Die Möglichkeiten, die mit Java bestehen, die hieraus resultierenden Architekturen der Anwendungssysteme sowie deren Einfluß
auf die Performance sollen im folgenden untersucht werden.
Die Analyse geht in folgenden Schritten vor:
•
Dedizierte Darstellung der einzelnen Client/Server-Architekturen, die in einem
Web-basierten Data-Warehouse involviert sind
1
•
Zusammenführung der Einzel-Architekturen zu einer Gesamt-Architektur, die für
ein Web-basiertes Data-Warehouse geeignet ist
•
Darstellung der Java-Datenbankschnittstelle JDBC (Java Database Connectivity)
•
Systemarchitekturen Web-basierter Data-Warehouse-System auf der Grundlage
von JDBC
•
Implementierung einer prototypischen Anwendung zu der dargestellten Architektur eines Web-basierten Data-Warehouses
Hierbei werden schwerpunktmäßig die Realisierungsalternativen unter Einbezug von Java betrachtet.
Client/Server-Architekturen
Protokolle: TCP/IP und HTTP
Alle Kommunikationsvorgänge, sowohl im Internet als auch im Intranet, basieren mehr oder minder direkt auf TCP/IP (Transmission Control Protocol/Internet Protocol). Diese Protokollfamilie
bildet somit auch die Basis von Web-basierten Data-Warehouses, in denen die beteiligten Komponenten über IP-Nummern angesprochen werden. Im Web wird das HTTP-Protokoll (Hypertext
Transmission Protocol) verwendet, das seinerseits wiederum auf TCP/IP aufsetzt.
Die TCP/IP-Protokollfamilie
Im Rahmen der zunehmenden Verbreitung entfernter Zugriffe auf unterschiedlichste Ressourcen
hat sich TCP/IP als Quasi-Standard unter den Protokollen durchgesetzt. Selbst die „WindowsWelt“ hat sich in zunehmendem Maße hierauf eingestellt.
TCP/IP ist eine Protokollfamilie, die die Grundlage für unterschiedlichste Dienste im Internet bildet. TCP und IP sind eigentlich zwei unterschiedliche Arten von Protokollen. Obwohl beispielsweise NFS (Network File System) gemeinhin als TCP/IP-Dienst angesehen wird, verwendet dieser
Dienst lediglich IP, aber kein TCP [vgl. EVAN95, DICK97].
Einige der bekanntesten TCP/IP-Dienste sind FTP (File Transfer Protocol), RLOGIN (Remote
Login), TELNET (Network Terminal Protocol), EMail (Electronic Mail) und HTTP.
Das HTTP-Protokoll
Mit dem Ziel, ein anwendungsfreundliches, schnelles und dementsprechend schlankes Protokoll für
verteilte Hypermedia-Systeme zu entwickeln, wurde Ende der achtziger Jahre am Schweizer Kernforschungszentrum CERN die Entwicklung des HTTP (Hypertext Transfer Protocol) begonnen.
Seit 1990 wird das Protokoll eingesetzt.
HTTP basiert auf einem zustandslosen Anfrage-/Antwort-Pradigma. Der Client schickt eine Anfrage in Form eines URL (Unified Resource Locator) an den Server. Der URL setzt sich aus dem
Übertragungsprotokoll (z.B. HTTP), der Adresse des Servers, der relativen Adresse im Dateisystem
des Zielrechners und dem Namen des gewünschten Dokuments zusammen. HTTP versieht diese
Anfrage mit verschiedenen Zusatzinformationen bezüglich der Protokoll-Version, einigen ClientInformationen und einigem mehr. Der Server, der Zielrechner, antwortet seinerseits in Form der
Übertragung des gewünschten Dokuments an den Client. Anschließend wird die Verbindung seitens des Servers sofort beendet. Client und Server stehen dann nicht mehr in Verbindung [vgl.
BERG96].
2- und 3-stufige Architekturen
Grundsätzlich sind zwei Formen von Client/Server-Architekturen zu unterscheiden, 2-stufige (2Tier) und 3-stufige (3-Tier) Architekturen.
2
Traditionelle Client/Server-Systeme, z.B. Datenbank-Client/Server-Systeme basieren auf einer 2stufigen Architektur, Datenbank-Server-Ebene und Client-Ebene.
Eine 3-stufige Architektur besteht aus den beiden o.g. Ebenen zuzüglich einer dazwischen befindlichen Schicht, der sogenannten Middleware oder Middle-Tier. Je nach Funkionalität des Gesamtsystems kann diese Schicht unterschiedlichste Aufgaben wahrnehmen.
Oftmals wird die Middleware genutzt, um Daten graphisch aufzubereiten oder speziell im Falle von
Datenbank-Anwendungen, um für die vom Client angeforderten Daten die für die Datenbank notwendigen SQL-Statements zu generieren. Der Client kann in diesen Fällen sehr schlank und unabhängig vom verwendeten Datenbanksystem gehalten werden [vgl. EVAN95]. Insbesondere bei
Web-Applikationen kann sich dieser Umstand positiv auf die Performance des Gesamtsystems
auswirken, da das über das Internet zu übertragende Datenvolumen drastisch gesenkt werden kann.
Die lokale Netzlast auf der Server-Seite kann sich dagegen steigern [vgl. DICK97].
Bezüglich Web-basierter Datenbank-Anwendungen, die mit Java realisiert und deren Frontends
(Applets) in einem Web-Browser ausgeführt werden, bietet eine 3-stufige Architekur weiterhin den
Vorteil, daß notwendige Programmodule nötigenfalls in native Code implementiert werden können,
ohne das es zu Kollisionen mit der in den Browsern implementierten Java-Security kommt. Die
Verwendung einer Middleware bietet zusätzlich den Vorteil größerer Flexibiliät und Skalierbarkeit,
wobei die Ebenen Server und Middle-Tier nicht notwendigerweise auf unterschiedlichen Rechnern
installiert sein müssen. Wenn die Anforderungen der Applikation nach Performance und Speicherbedarf steigen, kann leichter ein Server aufgerüstet werden, als dies seitens einer möglicherweise
unbekannten Anzahl von Clients zuzumuten, geschweige denn problemlos realisierbar wäre.
Schießlich lassen sich im Application-Server, der Middleware, zusätzliche Sicherheitsmechanismen implementieren. Datenbanken, die eventuell nicht mit TCP/IP als Übertragungsprotokoll arbeiten, von einem Java-Applet also nicht ansprechbar wären, können integriert werden. Der Application-Server würde dann neben anderen Aufgaben als Protokollumsetzer arbeiten.
Die Nachteile einer dritten Ebene sind ein erhöhter Management-, Entwicklungs- und Administrationaufwand. Die Fehlersuche bei der Implementierung wird komplizierter, weil die Lokalisierung
der Fehler erschwert wird [vgl. DICK97].
Die Vor- und Nachteile können wie folgt zusammengefaßt werden:
Vorteile
Nachteile
•
Entlastung der System-Clients, wodurch
die Entwicklung sogenannter Thin-Clients
möglich wird
•
•
Entlastung des globalen/lokalen Netzwerks •
•
Möglichkeit der physischen Trennung von
Web- und Datenbank-Server
•
Möglichkeit des Einsatzes nativer Komponenten auf dem Application-Server
•
Bessere Skalierbarkeit
•
Integrationsmöglichkeit zusäzlicher Sicherheitsmechanismen
•
Zusätzliche Serverlast und somit zuätzlicher Hardwarebedarf seitens des/der Server(s)
Erhöhter Entwicklungs-, Management- und
Administrationsaufwand
Möglicherweise Erhöhung des lokalen
Netzwerkverkehrs
Tabelle 1: Vor- und Nachteile 3-stufiger Anwendungs-Architekturen
3
Das World Wide Web
Abbildung 1 zeigt das Client/Server-Prinzip des Web auf Basis einfacher HTTP-Verbindungen ohne CGI (Common Gateway Interface) und ohne Einbindung von Nicht-HTTP-Protokollen. Hierbei
handelt es sich um eine 2-Tier-Architektur. Ein Web-Browser als Client nimmt Verbindung zu einem Web-Server auf, der seinerseits mittels Hyperlinks auf andere Web-Server verweisen kann.
Die gewünschten Dokumente werden, wie oben beschrieben, via HTTP an den Client übertragen.
Die Verbindung zwischen Client und Server wird nach erfolgter Übertragung der Dokumente abgebaut, eine neue Anfrage seitens des Clients führt dann zu einem erneuten Verbindungsaufbau
[vgl. BERG96].
WWW-Client
WWW-Client
WWW-Browser
WWW-Browser
HTTP
WWW-Server
HTTP
HTML-Link
HTTP
WWW-Server
Abbildung 1: Das Client/Server-Prinzip des WWW
Datenbankarchitekturen
Heutige Datenbankanwendungen werden, mit Ausnahme von Desktop-Datenbanken, ähnlich den
o.g. Web-Anwendungen nach dem 2-stufigen Client/Server-Prinzip betrieben. Abgesehen von integrierten Lösungen wie z.B. NCA (Network Computing Architecture von ORACLE), das eine 3Ebenen-Architektur realisiert, arbeiten alle Architekturansätze nach dem klassischen Client/ServerPrinzip, also einem Datenbank-Server und den entsprechenden Clients. Abbildung 2 stellt diese
Basis-Architektur graphisch dar [vgl. EVAN95].
Der Zugriff eines DB-Clients erfolgt in der Weise, daß die betreffende Datenbankanwendung ihre
Anfragen an die beim Client installierte Netzsoftware weiterleitet (z.B. SQL*Net bei ORACLE),
welche diese ihrerseits über die jeweilige Betriebssystem-Netzwerksoftware und das Betriebssystem des Clients bzw. des Servers an die Netzwerksoftware und anschließend an das DatenbankManagementsystem weiterleitet. Die Antwort, das Ergebnis der Anfrage, nimmt anschließend den
umgekehrten Weg zurück zum Client.
Neuere Versionen von Datenbank-Netzwerksoftware (z.B. SQL*Net V2 von ORACLE) bieten
noch weiterreichende Möglichkeiten. Hierbei werden Verbindungen über heterogene Netzwerke
hinweg protokollunabhängig (TCP/IP, DECNet, SPX/IPX etc.) und medienunabhängig (Ethernet,
Token Ring etc.) unterstützt [vgl. ORAC97]. Auch in Bezug auf Web-basierte Data-Warehouses ist
dieser Punkt nicht zu unterschätzen. Zwar erfolgt die Anfrage des Clients via HTTP, also TCP/IPbasiert, die Anbindung der Datenbank ist aber sowohl auf Protokollebene als auch physikalisch aus
Sicht des Clients unbestimmt oder zumindest variabel.
4
DB-Client
Datenbank-Anwendung
Datenbank-Netzsoftware
Betriebssystem-Netzsoftware
Betriebssystem
SQLAnfragen
Netzwerkprotokoll
(z.B. TCP/IP)
Daten
Betriebssystem
Betriebssystem-Netzsoftware
Datenbank-Netzsoftware
DB-Server
Datenbank-Anwendung
Abbildung 2: Einfaches DB-Client/Server-System
Die folgende Abbildung zeigt ein Szenario (ohne Web) mit drei Clients, die unter Verwendung
unterschiedlicher Protokolle auf einen ORACLE-Datenbankserver zugreifen. Da der Datenbankserver mit dem TCP/IP-Protokoll arbeitet, wurde ein MPI (Multi Protocol Interchange von
ORACLE), ein Protokollumsetzer, zwischengeschaltet. Das MPI-Modul extrahiert lediglich die tatsächlichen Nutzdaten aus dem jeweiligen Quellprotokoll und überträgt sie in das Zielprotokoll. Der
Overhead, der sonst bei einer Kapselung der Datenpakete entstehen würde, enfällt. Dies erhöht die
Performance und damit die Datendurchsatzrate im Netz erheblich [vgl. ORAC97].
DB-Client
DB-Client
SPX/IPX
MPI
DB-Client
DECNet
TCP/IP
MPI
DB-Server
Abbildung 3: Protokollkonvertierung mit SQL*Net V2 und MPI
Java-Client/Server-Architekturen: Remote Methode Invocation
Ein recht intensives Feld der Diskussion und Entwicklung ist die Realisierung verteilter objektorientierter Anwendungen. Als Stichworte seien hier CORBA (Common Object Request Broker Architecture), DCOM (Distributed Component Object Model von Microsoft) und RMI (Remote Method Invocation von Sun) genannt. Das vorrangige Ziel all dieser Bemühungen besteht letztlich
darin, die Rechenlast in geeigneter Form auf mehrere Hosts zu verteilen oder bestehende Anwendungen zu einer Gesamtapplikation zu integrieren.
5
Socket-Verbindungen, wenngleich mit Java ohne Probleme realisierbar, haben mit Objektorientierung, dem „Basis-Pradigma“ von Java und somit auch JDBC, nichts gemein, weshalb sie im folgenden nicht weiter betrachtet werden. Das Augenmerk wird auf RMI gerichtet, der Java-eigenen
Client/Server-Verbindung.
RMI benutzt TCP/IP und ist seit Java 1.1 standardmäßig im Package java.rmi enthalten. Für Java 1.02 gibt/gab es eine eigene Version. RMI ermöglicht die Ausführung und Kommunikation zwischen Java-Programmen in unterschiedlichen Adreßräumen. Die Analogie zu CORBA ist unverkennbar. CORBA ist im Gegensatz zu RMI aber interoperabel, also unabhängig von der verwendeten Programmiersprache, während RMI von einer homogenen Java-Umgebung ausgeht. Java
kann selbstverständlich in CORBA-Lösungen eingesetzt werden, RMI erlaubt jedoch eine konsistentere Modellierung, da die „Java-Welt“ nicht verlassen werden muß. Der Nachteil von JavaRMI ist, daß RMI gegenüber CORBA langsamer ist, denn Java lädt die benötigten Klassen via
HTTP, während CORBA das schnellere IIOP (Internet Inter-ORB Protocol) benutzt.
Gegenüber Socket-Verbindungen abstrahiert RMI von der Stream-Ebene und bietet dem Client die
Möglichkeit Methoden auf seiten des Servers anzusprechen. Dies ist einem RPC (Remote Procedure Call) sehr ähnlich. Der wesentliche Unterschied besteht in der Objektorientiertheit der RMI [vgl.
SUN98, ORFA98].
Schematisch kann das RMI-Modell wie folgt dargestellt werden [vgl. SUN98]:
Applikationen
RMISystem
Client
Server
Stubs
Skeleton
Remote Reference Layer
Transport
Abbildung 4: Das Java-RMI-System
Ein Methoden-Aufruf des Client wandert auf der Seite des Clients herunter bis auf die Transportebene des RMI-Systems, um dann auf der Seite des Server wieder herauf zu wandern und die entsprechende Aktion zu bewirken. Hierzu verwendet der Client einen sogenannten Stub (Stummel),
eine Client-seitige Referenz auf das Remote-Objekt. Der Stub ist eine Implementierung des Remote-Interfaces des Remote-Objekts. Ein Stub wird mit dem rmic-Compiler des JDK erzeugt. Der
Remote Reference Layer ist für die Interpretation der Semantik der Client-Anforderung sowie der
entsprechenden Antwort des Servers verantwortlich. Der Transport Layer kontrolliert den Aufbau,
die Unterhaltung sowie den Abbau der Verbindung zwischen Client- und Server-Objekt(en). Das
Skeleton bewirkt letzlich den Aufruf der angeforderten Methode beim Server-Objekt. Die Antwort
des Servers nimmt dann den umgekehrten Weg zurück zum Client [vgl. SUN98].
Architektur Web-basierter Data-Warehouses
In den vorangegangenen Abschnitten wurden die einzelnen Client/Server-Architekturen eines allgemeinen Web-Systems auf Basis von HTTP, eines Datenbanksystems und der Kommunikation
verteilter objektorientierter Systeme mit Java und RMI betrachtet. Zur Realisierung eines Web6
basierten Data-Warehouses müssen die Modelle geeignet miteinander kombiniert und zu einem
Modell integriert werden.
In den genannten Fällen spielte die räumliche Distanz zwischen Client und Server keine modellrelevante Rolle. Im Hinblick auf die Performance eines Web-basierten Data-Warehouses ist die Berücksichtigung der räumlichen Trennung sowie die Berücksichtigung der technischen Überbrükkung derselben mittels unterschiedlicher Netzwerke durchaus relevant. Ähnliches gilt für Flexibiliät der Planung und Implementierung eines nicht mehr modellhaften, sondern konkreten Systems.
Bei der Realisierung der Architektur für ein Web-basiertes Data Warehouse geht es im wesentlichen um die Frage, welche Aufgabe an welcher Stelle verrichtet werden und wieviele Datentransfers anfallen. Die Realisierung aller benötigten Server, Web-Server und Datenbank-Server bei 2stufiger Architektur sowie einem Java-Server (Application-Server) bei 3-stufiger Architektur, auf
einem gemeinsamen Rechner führt beispielsweise zu einer relativ geringen Netzwerkbelastung
zwischen den beteiligten Maschinen (ein Server plus n Clients); doch müßte der Server möglicherweise eine sehr hohe Performance besitzen, um den Anforderungen der Clients zu genügen, je nach
Anzahl, Abfragevolumina und Abfragekomplexität der Clients.
Daneben spielen Fragen des Aufwands und der Flexibilität bei der Realisierung des Systems, der
Verfügbarkeit kommerzieller Werkzeuge und vor allem der Bedarf an Installationen auf den Clients ein wichtige Rolle. Die folgende Liste enthält die wichtigsten Realisierungskriterien:
•
Performancebedarf bei dem/den Server(n)
•
Performancebedarf der Clients
•
Bedarf an Vorinstallationen bei den Clients
•
Realisierungsaufwand
•
Flexibilität der Realisierung
•
Verfügbarkeit kommerzieller Werkzeuge für die gewählte Architektur
[vgl. DICK97, ORFA98]
Realisierungsalternativen
Vor dem Verglich der möglichen Realisierungsalternativen sollen einige Überlegungen angestellt
werden, die die Anzahl der vernünftigen realisierbaren Alternativen einschränken:
•
Der WWW-Client ist in jedem Fall identisch mit dem Java-Client, d.h. es werden
nur Java-Applets betrachtet, die im Browser, dem WWW-Client ablaufen. Es gibt
somit nur einen Typ von Client des Gesamtsystems, dieser ist sowohl WWWClient als auch Java-Client. Im folgenden wird dieser als System-Client bezeichnet.
•
Der Java-Server fungiert in einem Web-basierten Data-Warehouse als Datenbank-Client. Der Zugriff auf die Daten und deren Visualisierung soll über Mechanismen des WWW bzw. Java erfolgen. Die Visualisierung der Daten über andere (datenbankspezifische) Werkzeuge setzt zum einen deren Installation auf
den Clients voraus, zum anderen sind diese Werkzeuge (z.B. ORACLE Reports
oder ORACLE Graphics) im allgemeinen nur für den direkten Zugriff auf den
Datenbank-Server ausgelegt [vgl. ORAC97]. Zugriffe via WWW sind mit ihnen
nicht möglich.
Damit sind die in Abbildung 5 darstellten Komponenten für die Realisierung des Architekturdesigns geeignet zu kombinieren.
7
Client
Middle-Tier
(Java-Server)
WWW-Server
DB-Server
Abbildung 5: Abläufe beim Systemzugriff eines Clients
Ein System-Client stellt eine Anfrage an den Web-Server und erhält ein HTML-Dokument mit einem eingebundenen Java-Applet zurück. Der Browser startet dieses Applet, welches sich entweder
direkt an den Datenbank-Server wendet oder aber an den Java-Server, der dann seinerseits die Anfrage an den Datenbank-Server startet. Der Datenbank-Server antwortet gegebenenfalls mit den
Abfrageergebnissen entweder direkt an den System-Client (2-stufige Architektur) oder an den JavaServer, welcher die Ergebnisse (möglicherweise in aufbereiteter Form) an den System-Client oder
in Form von HTML-Dokumenten an den WWW-Server weiterleitet (3-stufige Architektur). Im
letzten Fall müßte der System-Client darüber informiert werden, daß die Abfrageergebnisse in
Form eines HTML-Dokuments auf dem Server abgelegt wurden und abgerufen werden können.
Dies kann beispielsweise durch das Senden der Java-Methode showDocument() der Klasse java.applet.AppletContext geschehen.
Datenbankintegration mit JDBC
JDBC steht für Java Database Connectivity. JDBC ist eine Schnittstelle, die entwickelt wurde, um
den Bedarf nach einer standardisierten Java-Anwendungsschnittstelle zu relationalen DatenbankManagementsystemen zu befriedigen. JDBC gestattet den Zugriff auf relationale Datenbanken aus
Java-Anwendungen heraus. Diese Zugriffsmöglichkeiten sind sowohl von der Plattform, auf der die
Anwendung läuft, als auch vom zugrundeliegenden Datenbanksystem unabhängig. Die Spezifikation von JDBC ermöglicht das Erstellen von Java-Code zum Etablieren einer Datenbankverbindung,
zum Versenden von SQL-Statements an die Datenbank und zum Retrieval von Abfrageergebnissen, Metadaten und Statusmeldungen der Datenbank. Daneben bietet JDBC Möglichkeiten der Typumwandlung von Java- und SQL-Datentypen, zur Behandlung von SQL-Cursors, zum Transaktionsmanagement, der Verwendung von Stored Procedures und einigem mehr.
Die Entwicklung der JDBC-API (API – Application Program Interface) wurde bei JavaSoft, einer
zur Java-Weiterentwicklung gegründeten Tochterfirma von Sun, im Januar 1996 initiiert. Eine erste
Testversion wurde im März 1996 freigegeben. Seit Version 1.1 ist JDBC fester Bestandteil des
JDK (Java Developement Kit) [vgl. SUN98].
JDBC-Treiber
JavaSoft unterteilt die JDBC-Treiber in vier Kategorien:
•
Typ 1 - ODBC Bridge-Treiber (ODBC – Open Database Connectivity):
Die ODBC-Bridge-Treiber übersetzen JDBC-Aufrufe in ODBC-Anfragen auf der ClientMaschine. Der Einsatz dieser Treiber hat den Aufruf nativer ODBC-Methoden zur Folge.
8
Die hierzu notwendigen ODBC-Treiber müssen auf der Client-Maschine installiert sein,
sie können nicht über das Web geladen werden.
•
Typ 2 – Native API Partitial Java-Treiber:
Dieser Treibertyp übersetzt JDBC-Aufrufe direkt für die Datenbank-spezifischen Aufrufe
der jeweiligen Datenbank-API. Es handelt sich hierbei um native Treiber, die auf der Client-Maschine installiert sein müssen.
•
Typ 3 – Net Protocol All-Java-Treiber:
Diese Treiber sind vollständig in Java implementiert, so daß sie vom Web-Client über das
Netz geladen werden können. Der Client nimmt in diesem Fall Kontakt zu einem Server
auf, der die JDBC-Aufrufe in native Datenbank-Aufrufe übersetzt. Diese Lösung setzt das
Vorhandensein entsprechender Middleware voraus.
•
Typ 4 – Native Protocol All-Java-Treiber:
Diese Treiber sind vollständig in Java implementiert, erlauben aber dennoch die direkte
Kommunikation mit dem Datenbank-Server. Da die Treiber in Java geschrieben sind, könen sie über das Netz auf den Web-Client geladen werden.
Die Treiber-Kategorien 1 und 2 wurden im wesentlichen in der Anfangszeit von JDBC entwickelt,
um unter Ausnutzung bestehender Komponenten raschen Zugang zu Datenbanken seitens Java zu
ermöglichen, Java also Datenbank-fähig zu machen. JavaSoft bezeichnet die Treiber der Typen 3
und 4 als die geeignetsten Lösungen. Jeder clientseitig verwendete Native-Code unterminiert den
einzigartigen Vorteil von Java: die Inter- bzw. Intranetfähigkeit. Nativer Code kann nicht über das
Netz geladen werden, er muß vielmehr bei jedem Client installiert werden, was nicht immer gewünscht oder gar möglich ist [vgl. DICK97].
JDBC-Treiber-Architekturen
In Abhängigkeit der verwendeten Treiber-Typen ergeben sich für JDBC-Anwendungen unterschiedliche Architekturen. An dieser Stelle sollen lediglich die grundsätzlichen Möglichkeiten diskutiert werden, d.h. ohne Einschluß von Socket- oder RMI-Verbindungen zwischen Applet und
JDBC-Treiber-Manager. Eine derartige Verbindung hat zur Folge, das Applet und ApplicationServer, der den JDBC-Treiber-Manager beinhaltet, zu einer Netzwerkverbindung wird, so daß
hierbei generell eine 3-stufige Architektur zum Tragen kommt. Dies hat wiederum zur Folge, daß
unabhängig vom verwendeten Treiber, keinerlei nativer Code zum Web-Client geladen werden
muß.
JDBC-Treiber-Architektur mit Typ-1-Treibern
Bei Abbildung 6 handelt es sich um eine 2-stufige Achitektur. Die Java-Komponenten werden zum
Client geladen, auf dem die restlichen Kompontenten für den Datenbankzugriff installiert sein müssen. Die einzige Netzwerkverbindung besteht zwischen der nativen Datenbank-Bibliothek und dem
Datenbank-Server.
Die Java-Applikation oder das Java-Applet stehen über den JDBC-Treiber-Manager und die JDBCODBC-Bridge in Verbindung mit einer nativen ODBC-Schnittstelle. Ab hier wird ausschließlich
ODBC verwendet. Der ODBC-Treiber-Manager wählt den geeigneten, vorkonfigurierten Treiber
aus, der direkt über die native Datenbank-Bibliothek mit der der Datenbank kommuniziert [vgl.
DICK97].
Folgende Eigenschaften zeichnen diese Architektur aus:
•
Der notwendige ODBC-Treiber muß beim Client installiert sein.
•
Native Datenbank-Bibliotheken müssen auf dem Client installiert sein.
9
•
Sämtliche Prozesse mit Ausnahme derer des Datenbank-Servers laufen beim Client ab.
Java-Applet
JDBC-Treiber-Manager
JDBC-ODBC-Bridge
ODBC-Treiber-Manager
ODBC-Treiber
Datenbankserver
Abbildung 6: JDBC-Architektur mit Typ-1-Treibern
JDBC-Treiber-Architektur mit Typ-2-Treibern
Auch hierbei handelt es sich um eine 2-stufige Architektur, bei der alle Prozesse mit Ausnahme derer des Datenbank-Servers beim Client ablaufen. Im Gegensatz zur Architektur mit Typ-1-Treibern
sind hier die ODBC-Komponenten durch native Schnittstellen zwischen JDBC-Treiber-Manager
und nativer Datenbank-Schnittstelle ersetzt [vgl. DICK97].
Java-Applet
JDBC-Treiber-Manager
Native API Partitial Java-Treiber
Native API
Datenbankserver
Abbildung 7: JDBC-Architektur mit Typ-2-Treibern
Diese Architektur besitzt folgende Eigenschaften:
•
Es werden keine ODBC-Treiber benötigt.
•
Native Bibliotheken und JDBC-Treiberschnittstellen müssen lokal auf dem Client installiert sein.
10
•
Alle Prozesse mit Ausnahmen derer des Datenbank-Servers laufen auf dem Client ab.
JDBC-Treiber-Architektur mit Typ-3-Treibern
Bei Treibern vom Typ 3 ist eine Middleware zwingend erforderlich. Auf dem Client wird keine
nativer Code verwendet, dieser ist auf den Middle-Tier-Server ausgelagert. Die Verbindung von
Middleware und Datenbank wird über native Datenbank-Bibliotheken oder alternativ durch ODBC
realisiert [vgl. DICK97].
Java-Applet
JDBC-Treiber-Manager
Net Protocol All Java-Treiber
Middle-Tier (ODBC oder Native API)
Datenbankserver
Abbildung 8: JDBC-Architektur mit Typ-3-Treibern
Folgende Eigenschaften kennzeichnen diese Architektur:
•
Es handelt sich immer um eine 3-stufige Architektur.
•
Auf dem Client werden keinerlei native Komponenten benötigt, weshalb auch
sogenannte Thin-Clients Verwendung finden können. Alle nativen Komponenten
werden auf der Middleware installiert.
•
Prozesse können geeignet zwischen Client und Middleware aufgeteilt werden.
Kriterien für die Aufteilung können bespielsweise die Performance von Client
und Server sein.
JDBC-Treiber-Architektur mit Typ-4-Treibern
Diese Architekur beinhaltet keinen nativen Code, alle Komponenten sind in Java implementiert.
Der Zugriff auf die Datenbank erfolgt über deren originäre Schnittstelle. Die Hauptlast liegt beim
Client, sofern eine 2-stufige Architektur, wie in Abbildung 9 darstellt, gewählt wird [vgl. DICK97].
Somit läßt sich die Architektur wie folgt charakterisieren:
•
Es werden keine ODBC-Treiber benötigt.
•
Alle Komponenten sind in Java implementiert, so daß Applets diese über das
Netz laden können. Vorinstallationen auf dem Client entfallen.
•
Alle Prozesse werden mit Ausnahme derer des Datenbank-Servers beim Cleint
ausgeführt.
11
Java-Applet
JDBC-Treiber-Manager
Net Protocol All Java-Treiber
Datenbankserver
Abbildung 9: JDBC-Architektur mit Typ-4-Treibern
Kommunikation im Web-basierten Data-Warehouse
Die im folgenden diskutierte Form der Kommunikation stellt nur eine mögliche Alternative unter
vielen dar. Die oben beschriebenen JDBC-Treiber-Architekturen lassen viele Alternativen zu.
Betrachtet man nochmals die im Abschnitt „2- und 3-stufige Architekturen“ genannten Vor- und
Nachteile 2- bzw. 3-stufiger Architekturen unter dem eingrenzenden Aspekt der Web-Tauglichkeit
einer Data-Warehouse-Anwendung, so bietet sich die 3-stufige Architekur als geeignetste Lösung
an.
•
Nativer Code auf dem Client ist nicht notwendig.
•
Client-seitige Installationen bezüglich Datenbank-Treibern sind nicht erforderlich, unabhängig vom gewählten JDBC-Treiber. Für Web-basierte Anwendungen
im Internet ist dies ein großer Vorteil.
•
Für die Clients entsteht keinerlei Administrationsaufwand, da alle benötigten
Komponenten über das Netz geladen werden können.
•
Die Architektur bietet ein hohes Maß an Flexibilität. Dies geht soweit, daß die
Client-Applikation vollkommen von der Datenbank abstrahieren kann, so daß der
Wechsel der Datenbank und/oder der JDBC-Treiber keinerlei Einfluß auf die
Client-Anwendung besitzt. Dies ist insbesondere unter Wartungsaspekten vorteilhaft.
•
Durch die Aufteilung der Komponenten, kann die Netzlast in Richtung des Clients gering gehalten werden. Das Applet braucht keine Datenbanktreiber oder
ähnliches zu laden. Somit sind auch langsame Netzwerkverbindungen, wie z.B.
Modemverbindungen, noch für eine effiziente Data-Warehouse-Nutzung geeignet.
•
Die Client-Anwendung, das Applet, kann vergleichsweise schlank implementiert
werden, da die Zugriffsmechanismen auf die Datenbank auf die Middleware ausgegliedert werden können. Somit ist diese Architektur auch für Thin-Clients geeignet.
Nachteilig wirkt sich lediglich der gegenüber einer 2-stufigen Architektur erhöhte Komplexitätsgrad aus, der die Entwicklung und Fehlerbeseitigung komplizierter werden läßt.
12
Client
Applet
HTTP
RMI
Middle-Tier
(Java-Server)
WWW-Server
JDBC-Connection
Data Warehouse
DB-Server
Abbildung 10: Kommunikation in einem Web-basierten Data-Warehouse bei 3-stufiger Architektur
Die Kommunikation zwischen dem Client und dem WWW-Server findet, wie in Abschnitt „Das
World Wide Web“ dargestellt, über das HTTP-Protokoll statt. Der Übergang zu Java erfolgt über
Applets, die gemeinsam mit den HTML-Dokumenten übertragen werden. Das Applet stellt den eigentlichen Client in Bezug auf die Data-Warehouse-Anwendung dar, der dann seinerseits mittels
Sockets oder RMI1 mit dem Application-Server kommuniziert.
Der Application-Server beinhaltet die JDBC-Komponenten, die dann je nach Wahl des Treibertyps,
mit dem Datenbankserver kommunizieren.
Ob zur Realisierung dieser Architektur auf der Server-Seite ein, zwei oder mehr Maschinen eingesetzt werden, ist abhängig von der Systembelastung und der Leistungsfähigkeit der dort eingesetzten Maschine(n). Bei komplexen Systemen erscheint es sinnvoll, einen Rechner als Java-Server
(Application-Server) und einen Rechner als Datenbank-Server einzusetzen. Der WWW-Server
kann sich zusätzlich auf dem Datenbank-Server befinden. Die Aufteilung des Systems auf mehr
Maschinen ist theoretisch denkbar, logische Gründe, die dies zwingend erfordern, gibt es aber
nicht. Eine weitere Verteilung ist vielmehr eine Frage der Leistungsfähigkeit der Server und der
gewünschten Ausfallsicherheit des Systems. Insbesondere letztere kann sogenannte Fall-BackServer, die den Ausfall eines anderen Server kompensieren, in dem sie dessen Aufgaben übernehmen, erfordern.
JDBC in der Praxis
Grundlagen der Verwendung von JDBC
JDBC bietet eine reichhaltige Anzahl an Klassen und Schnittstellen, um mit Datenbanken zu kommunizieren, so daß diese hier nicht erschöpfend vorstellt und diskutiert werden können. Die folgenden Darstellungen konzentrieren sich daher auf die notwendigsten Kenntnisse zu JDBC, die für
die Realisierung eines Web-basierten Data-Warehouses nötig sind.
Die Driver-Schnittstelle
JDBC stellt zwei verschiedene Objekte zur Verwaltung von Datenbanktreibern bereit. Das erste
Objekt ist die Driver-Schnittstelle.
1
Andere Formen der Kommunikation, z.B. CORBA, sind möglich. Diese werden hier aber nicht betrachtet, da sich die
Darstellung auf Java konzentriert.
13
Die Driver-Schnittstelle bietet verschiedene Methoden zur Ermittlung von Informationen über
den aktuellen Datenbanktreiber sowie die Bereitstellung der connect()-Methode, die ein Connection-Objekt erzeugt, welches für den Datenbank-Zugriff genutzt werden kann.
Die Driver-Schnittstelle bietet folgende Methoden an [vgl. HOBB97, SUN98]:
Methode
Beschreibung
acceptsURL()
Gibt einen Booleschen Wert zurück, der anzeigt, ob der Treiber
eine Verbindung zur gewünschten Datenbank, die mittels des URL
spezifiziert wurde, aufbauen konnte.
connect()2
Erstellt eine Verbindung zur Datenbank und gibt ein Connection-Objekt zurück, das in der Anwendung für die weiteren Operationen auf der Datenbank genutzt wird.
getMajorVersion()
Ermittelt die Hauptversion des Treibers.
getMinorVersion()
Ermittelt die Unterversion des Treibers.
getPropertyInfo()3
Ermittelt die Eigenschaften, die ein Anwender haben muß, um mit
dem aktuellen Treiber eine Verbindung zur Datenbank einrichten
zu können.
jdbcComplient()
Gibt einen Booleschen Wert zurück, welcher anzeigt, ob das aktuelle Driver-Objekt JDBC-konform ist, also der von Sun definierten
Schnittstellenbeschreibung folgt.
Tabelle 2: Methoden der Driver-Schnittstelle
Das DriverManager-Objekt
Die Klasse DriverManager stellt Dienste für die Verwaltung von Driver-Objekten bereit.
Hierzu wird auf die Systemeigenschaft jdbc.driver zurückgegriffen. Damit können für verschiedene Anwendungen unterschiedliche Treiber zur Laufzeit spezifiziert werden.
Die folgende Tabelle zeigt die Methoden des DriverManager-Objekts [vgl. HOBB97, SUN98]:
Methode
2
3
Beschreibung
deregisterDriver()
Entfernt ein Driver-Objekt aus der Liste der Treiber.
getConnection()
Richtet eine Verbindung zur Datenbank ein.
getDriver()
Ermittelt ein Driver-Objekt, das eine Verbindung zum angegebenen URL herstellt.
getDrivers()
Gibt ein Array mit allen aktuell beim Manager registrierten
Driver-Objekten zurück.
Diese Methode kann zum Aufbau einer Datenbankverbindung genutzt werden, obwohl die Methode getPropertyInfo() nicht immer unterstützt wird. (siehe Fußnote zur Methode getPropertyInfo()).
getPropertyInfo() wird nicht immer unterstüzt, beispielsweise vom ODBC-Treiber für Access 97. Bei den hier
verwendeten Entwicklungsumgebungen konnte folgendes festgestellt werden. Das SDK 3.0 für Java von Microsoft liefert trotz mangelnder Unterstützung des Treibers keine Ausnahme, es wird lediglich ein leeres Feld mit Eigenschaften
geliefert. Das JDK 1.1.6 von Sun liefert jedoch eine entsprechende Ausnahme, die die fehlende Unterstützung des Treibers bemängelt.
14
Methode
Beschreibung
getLoginTimeout()
Ermittelt, wie lange ein Treiber auf die Etablierung einer Verbindung wartet.
getLogStream()
Ermittelt den vom Manager verwendeten Log-Stream.
println()
Stellt den angegebenen String in den Log-Stream.
registerDriver()
Registriert den angegebenen Treiber beim Manager.
setLoginTimeout()
Bestimmt, wie lange der Treiber auf die Etablierung einer Verbindung warten soll.
setLogStream()
Setzt den Log-Stream.
Tabelle 3: Methoden des DriverManager-Objekts
Verbindung zur Datenbank: Die Connection-Schnittstelle
Das Connection-Objekt ist das wichtigste Objekt für die Einrichtung einer DatenbankVerbindung. Die Connection-Schnittstelle von JDBC stellt Methoden für die Verwaltung der
Transaktionsverarbeitung, zum Erzeugen von Objekten für die Ausführung von SQL-Anweisungen
sowie zum Erstellen von Objekten für die Ausführung von Stored Procedures bereit. Darüber hinaus bietet sie grundlegende Methoden zur Behandlung von Fehlern, die in Verbindung mit der Datenbank-Kommunikation auftreten können.
Ein Connection-Objekt kann sowohl mit den Methoden der Driver-Klasse, als auch mit dem
DriverManager erzeugt werden (siehe oben und Beispiele im Anhang).
Die folgende Tabelle zeigt die Methoden des Connection-Objekts [vgl. HOBB97, SUN98]:
Methode
4
Beschreibung
clearWarnings()
Löscht aktuelle Warnungen bezüglich der Verbindung.
close()
Schließt eine Datenbank-Verbindung.
commit()
Veranlaßt ein COMMIT. – Nur sinnvoll, wenn AutoCommit auf
false steht.
createStatement()
Erzeugt ein Statement-Objekt, welches zur Ausführung von
SQLs verwendet werden kann.
getAutoCommit()
Gibt den Status von AutoCommit wieder (true oder false).
getCatalog()4
Gibt eine String zurück, der den aktuellen Katalog der Verbindung
wiedergibt.
getMetaData()
Dient zur Ermittlung von Meta-Informationen zur Verbindung.
getTransactionIsolation()
Gibt den Isolation-Level/Modus einer Transaktion für die aktuelle
Verbindung zurück.
Diese Methode kann nur auf Datenbanken angewendet werden, die das Konstrukt des Kataloges unterstützen (z.B.
dbAnywhere). Oracle besitzt beispielsweise keine Kataloge.
15
Methode
Beschreibung
getWarnings()
Gibt die aktuellen Warnungen zurück.
isClosed()
true, wenn die Verbindung geschlossen wurde, sonst false.
isReadOnly()
Gibt true zurück, wenn die Verbindung Read-Only ist oder nicht
aktualisiert werden kann, sonst false.
nativeSQL()
Gibt SQL-Anweisungen so zurück, wie sie der JDBC-Treiber der
Datenbank präsentiert.
prepareCall()
Gibt eine CallableStatement-Objekt zurück, welches zur
Ausführung gespeicherter Prozeduren verwendet wird.
prepareStatement()
Gibt eine PreparedStatement-Objekt zur Ausführung dynamischer SQL-Anweisungen zurück.
rollback()
Bewirkt einen Rollback. – Nur sinnvoll, wenn AutoCommit auf
false gesetzt ist, da sonst nicht möglich bzw. wirkungslos.
setAutoCommit()
Setzt den Status/Modus für AutoCommit.
setCatalog()5
Setzt den aktuelle Katalog für die Verbindung.
setReadOnly()
Setzt eine Verbindung in den Modus Read-Only, d.h. es sind keine
Aktualisierungen erlaubt.
setTransactionIsolation()
Setzt den Isolation-Level für eine Transaktion der aktuellen Verbindung.
Tabelle 4: Methoden der Connection-Schnittstelle
Projekt: Abenteuer und Freizeit
Projektbeschreibung
Im folgenden soll anhand einer prototypischen Web-Anwendung die bislang erläuterte Theorie
umgesetzt werden. Als Beispiel soll ein Outdoor-Unternehmen, „Abenteuer und Freizeit“, dienen,
welches in verschiedenen Ländern Niederlassungen unterhält. Innerhalb eines Applets sollen die
Umsatzdaten (Umsatz, Kosten) für alle Produkte gemäß einem Land oder mehrerer zu spezifizierender Länder ausgewertet werden.
Die Anwendung wird bewußt einfach gehalten, es wird lediglich eine Abfragemöglichkeit realisiert, bei der Umsätze und Kosten bezüglich eines oder mehrerer interessierender Länder vom Anwender spezifiziert werden können. Die Darstellung der Abfrageergebnisse erfolgt in Form einer
einfachen Liste, die die zurückgelieferten Datensätze enthält. Graphische Features werden nicht
implementiert. Damit erfüllt der Prototyp zwar nicht die Anforderungen an Data-WarehouseAnwendungen, die wesentlichen Charakteristika der Implementierung einer entsprechenden Anwendung werden aber deutlich. Um eine „echte“ Data-Warehouse-Anwendung daraus zu entwikkeln, müssen lediglich die Abfrage-Möglichkeiten sowie die Ergebnisaufbereitung erweitert werden. Die wesentlichen Komponenten zur Realisierung einer 3-stufigen Architektur sind vorhanden.
Um die Flexibilität der Architektur zu testen, soll die Anwendung mit verschiedenen Datenbanken,
ORACLE 7.3.3 und Microsoft Acces 976, realisiert und getestet werden.
5
Siehe Fußnote 4
16
Anwendungsarchitektur
„Abenteuer und Freizeit“ realisiert aufgrund der herausgearbeiten Vorteile eine 3-stufige Anwendungsarchitektur (siehe Abbildung 10: Kommunikation in einem Web-basierten Data-Warehouse
bei 3-stufiger Architektur, Seite 13). Das Frontend, das Applet, kann so unabhängig von der verwendeten Datenbank implementiert werden. Treiber für die Datenbank sind somit auf der Seite des
Clients nicht erforderlich, müssen also weder vorinstalliert noch zur Laufzeit geladen werden. Das
Frontend kann damit auf jedem Rechner, der über eine entsprechende TCP/IP-Verbindung zum
Web-Server und einen Java-fähigen Web-Browser verfügt, ausgeführt werden. Die Netzwerkbelastung ist aufgrund der Unabhängigkeit von der Datenbank und eventuell damit verbundenen Treibern minimal.
Abfragen richtet das Applet via RMI an einen ebenfalls in Java realisierten Applikations-Server.
Dieser verfügt über die notwendigen JDBC-Treiber, die zur Kommunikation mit der Datenbank erforderlich sind. Er generiert das erforderliche SQL-Statement, schickt dieses an die Datenbank und
bereitet das Resultat auf. Das aufbereitete Ergebnis wird dann an das anfordernde Applet versendet.
Der Applikations-Server ist so gestaltet, daß für jede Anfrage ein einzelner Thread gestartet wird.
Der Server ist somit Mehrbenutzer-fähig. Wenn verschiedene Anwender Anfragen an den Server
schicken, so bearbeitet dieser alle Anfragen parallel, so daß kein Anfrager auf die Abarbeitung einer Anfrage eines anderen Anwenders warten muß.
Relationales Datenmodell
Das Datenmodell ist entspricht einem (sehr) einfachen Star-Schema, welches auch komplexere
Auswertungen zuläßt, als sie im Applet des Prototypen realisiert werden.
Abbildung 11: Datenbank-Design des Prototypen „Abenteuer und Freizeit“
Die Tabelle UMSAETZE stellt die Faktentabelle dar. Sie ist insoweit denormalisiert, als sie die
Zeitdimension mit der Hierarchie BESTELLDATUM-MONAT-QUARTAL-JAHR enthält. Als
weitere hierarchische Dimensionen sind LAENDER (LAND-REGION) und PRODUKTE (PRODUKT-PRODUKTREIHE-PRODUKTTYP) realisiert.
Wie bereits oben erläutert, macht der implementierte Prototyp von den Auswertungsmöglichkeiten,
3-dimensionale Analyse über unterschiedliche Aggregationsstufen mit entsprechenden Drill-Ups/Downs, des Datenmodells keinen Gebrauch.
Java-Klassen-Design
Das Klassen-Design ist entsprechend den geringen Anforderungen einfach gehalten. Das Applet
kommuniziert mit dem Java-Server, welcher für jede Anfrage einen Thread (AUFInfoThread)
generiert.
6
Microsoft Access 97 ist zwar keine Server-Datenbank, ermöglicht aber die Demonstration des Prototypen in der Seminarveranstaltung, weshalb es hier als Datenbank verwendet wird.
17
Für die Kommunikation mit der Datenbank wurde die Klasse DBConnection implementiert, die
zum einen den Aufbau, Abbau der Datenbankverbindung und die notwendige Kommunikation mit
dieser realisiert, zum anderen aber auch mittels der Klasse Protocol alle Aktivitäten aufzeichnet.
Letzteres ist insbesondere in der Entwicklungs- und Test-Phase eine nicht zu unterschätzende Hilfe
bei der Fehlersuche.
Die folgende Abbildung zeigt die implementierten Klassen in Zusammenhang mit der relaisierten
Architektur:
AUFApplet.class
RMI
HTTP
AUFServerImp.class
AUFInfoThread.class
WWW-Server
Protokoll
DBConnection.class
Protocol.class
JDBC-Connection
= Java
Data Warehouse
DB-Server
Abbildung 12: Klassendesign im Zusammenhang mit der Architektur des Prototypen
Bewertung des Prototypen
Im Vergleich zur Realisierung einer Data-Warehouse-Anwendung mit den üblichen (nicht Webfähigen) Werkzeugen, übersteigt der Aufwand der hier vorgestellten Java-Implementierung den ersteren um ein vielfaches, ohne auch nur annähernd die Funktionalitäten erreichen zu können. Der
Grund hierfür liegt in der (noch) mangelnden Unterstützung Data-Warehouse-spezifischer Konstrukte wie z.B. Kreuztabellen, Drill-Up und Drill-Down und ähnlichem mehr. Würden diese in
Form von Bibliotheken zur Verfügung stehen, so könnte der Entwicklungsaufwand drastisch verringert werden. Dennoch bleibt zu erwarten, daß solange keine echte Werkzeug-Unterstützung
(z.B. durch entsprechende CASE-Tools) gegeben ist, die Entwicklungsaufwendungen und somit
die Kosten vergleichsweise hoch bleiben werden. Inwieweit dies ökonomisch vertretbar ist, muß im
Einzelfall anhand vergleichender Kalkulationen ermittelt werden.
Mangels „gleicher“ Anwendungen, die mit unterschiedlichen Technologien entwickelt wurden,
kann eine Bewertung der Performance nicht durchgeführt werden. Ein mit PowerPlay von der Firma Cognos, Inc. entwickelter Prototyp, der zudem noch deutlich mehr an Funktionalität bietet
(Traversieren der Hierarchien, wahlfreie Selektion interessierender Attribute, verschiedene graphische Auswertungen etc.) arbeitet jedoch erheblich schneller7. Die Ergebnisaufbereitung wird unterhalb einer Sekunde erreicht, während der hier vorgestellte Prototyp etwa 3 Sekunden für eine einfache Abfrage benötigt. Dieser Vergleich ist jedoch insofern unfair, als die PowerPlay-Variante nur
im Intranet eingesetzt werden kann, eine Verwendung in Zusammenhang mit dem Web ist nicht
möglich. Weiterhin wäre die Leistung des Prototypen steigerbar, wenn nicht nach jeder Abfrage die
Verbindung zur Datenbank abgebaut und somit bei jeder neuen Anfrage erneut aufgebaut werden
müßte. ORFALI und HARKEY, die ausgedehntere Experimente durchgeführt haben, bescheinigen
der 3-stufigen Architektur mit Java aber eine sehr gute Performance, die anderen Implementierungstechnologien, insbesondere CGI, überlegen ist. Allerdings empfehlen sie den Einsatz von
CORBA statt RMI, da CORBA schneller ist. Sie weisen aber darauf hin, daß Java noch nicht aus-
7
Screenschot siehe Anhang S. 38
18
gereift genug ist, um diesen Vergleich als entgültig betrachten zu können. Zukünftige JavaEntwicklungen können hier noch aufholen [vgl. ORF98].
Eines hat sich aber gezeigt, durch die Wahl der 3-stufigen Architektur konnte bei der Implementierung des Frontends komplett von der zugrundeliegenden Datenbank abstrahiert werden. Der Application-Server konnte durch Modifikation des verwendeten JDBC-Treibers sowie der Anpassung
des URL ohne weitere Änderungen an die verwendeten Datenbanken angepaßt werden. Durch eine
elegantere Implementierung, durch Verwendung von Kommandozeilenparametern oder Properties,
kann eine Sourcecode-Modifikation sogar komplett vermieden werden.
Durh die Wahl von Java für die Implementierung ist das System Plattform-unabhängig und Webtauglich. Dies wäre mit den klassischen Werkzeugen, sieht man von den aktuell auf dem Markt erscheinenden ab, die ebenfalls auf Java basieren, nicht möglich gewesen.
Schlußbetrachtung und Ausblick
Die Diskussion über die Anwendungs-Architekturen hat deutlich gezeigt, daß 3-stufige Architekturen für Data-Warehouse-Applikationen am geeignetsten sind. Java unterstützt die Architektur-Form
hervorragend, da alle notwendigen Klassen, z.B. für die Netzwerkkommunikation, zum JavaStandard gehören. Dank der Implementierung in Java könen Data-Warehouse-Anwendungen unabhängig von Rechnerplattformen entwickelt werden. Durch den Einsatz von Web-Technologie entfällt das Distributionsproblem der Anwendungen.
Allerdings ist der Implementierungsaufwand nicht unerheblich. Insbesonder die Realisierung graphischer Benutzeroberflächen ist außerordentlich aufwendig. In Bezug auf die im DataWarehousing gewünschte Flexibilität der Datenauswahl, -auswertung und -aufbereitung fehlt es an
geigneten Klassen und Konstrukten. Ohne eine entsprechende Klassenbibliothek muß alles notwendige von Hand implementiert werden.
Für größere Projekte oder Firmen, die Data-Warehouse-Lösungen in Form von Dienstleistungen
erstellen, ist es somit anzuraten, eine Bibliothek zu entwickeln oder anzuschaffen, die über die im
Data-Warehousing erforderlichen Klassen verfügt. Ansonsten besteht die Gefahr, daß die erhöhten
Entwicklungskosten die genannten Vorteile überkompensieren, so daß der Einsatz von Java ökonomisch nicht mehr sinnvoll ist. Derzeit werden derartige Bibliotheken auf dem Markt nicht angeboten, so daß Eigenentwicklungen erforderlich sind, die sich aber nur für Beratungsfirmen oder
ähnliches rentieren dürften. Hier besteht noch Handlungsbedarf seitens der Software- bzw. Werkzeug-Anbieter.
Die Verwendung von Web-Clients macht zudem eine Integration unternehmens-externer Informationsnachfrager möglich. Dies war bislang nur eingeschränkt möglich, da die bisherige ClientSoftware den externen Informationsnachfragern nur selten zur Verfügung stand.
Insgesamt bleibt festzuhalten, das Java bzw. Werkzeuge, die Java nutzen, interessante Perspektiven
für die Entwicklung von Data-Warehouse-Anwendungen bieten. Sie eröffnen die Möglichkeit, ein
und dieselbe Anwendung sowohl intern (Intranet) als auch extern (Internet) verfügbar und nutzbar
zu machen. In keinem Fall sind Vorinstallationen auf den Clients erforderlich, so daß die bislang
existierende Distributionsproblematik der Software entfällt.
Literaturverzeichnis
[BERG96] Bergmann, U.: WWW – Anbieten und Nutzen, Hanser Verlag, 1996
[DICK97]
Dicken, Hans: JDBC – Internet-Datenbankanbindung mit Java, Thomson Publishing,
1997
[EVAN95] Evans, C., Lacey, D., Harvey, D., Gibbons, D., Krasum, D.: Client/Server, Prentice
Hall, 1995
19
[ORFA98] Orfali, R., Harkey, D.: Client/Server Programming with Java and CORBA, John Wiley & Sons, Inc., Second Edition, 1998
[HOBB97] Hobbs, A.: Teach Yourself Database Programming with JDBC in 21 Days, SAMS
Publishing, 1997
[KIMB96] Kimball, R.: The Data Warehouse Toolkit, John Wiley & Sons, Inc. 1996
[ORAC97] unbekannter Verfasser: Online-Dokumetation zu ORACLE 7.3.3, 1997
[SUN98]
unbekannter Verfasser: HTML-Dokumentation zum JDK 1.1.6 von Sun Microsystems, Inc., 1998
[THIE98]
Thiemann, Uwe: Das Wesentliche an den Daten, erschienen in Byte, August 1998, S.
64-71.
[WHIT98] White, Colin: Information at your Browser-Click, erschienen in Byte, August 1998, S.
57-63.
Anhang
Hinweise zu den Programmbeispielen
Neben dem Prototypen, „Abenteuer und Freizeit“, werden im folgenden werden 2 Anwendungen
vorgestellt, die die Kommunikation über Sockets und RMI demonstrieren. Die Anwendungen zur
Verwendung von JDBC sowie zum Web-basierten Data-Warehouse verwenden die JDBC-ODBCBridge in Verbindung mit Microsoft Access 97. Durch Abwandlung der verwendeten JDBCTreiber sowie den damit verbundenen Änderungen an den URLs können die Beispiele aber mit beliebigen Datenbanken, für die JDBC-Treiber vorliegen, genutzt werden.
20
Client-/Server-Kommunikation via Sockets
Das folgende Beispiel demonstriert die Netzwerk-Kommunikation über Sockets. Ein Applet schickt
eine Zeichenkette an einen Server, welcher als Antwort die empfangene Zeichenkette in modifizierter Form an das Applet zurücksendet.
SocketServer.java
/*
* SocketServer
*
* Einfaches Beispiel für einen Socket-Server
*
* Copyright (c) 1998 by Karsten Brodmann
*/
import java.io.*;
import java.net.*;
class SocketServer {
public static void main(String args[]) throws IOException {
int
timeout = 2000;
// Timeout nach 2000 Sekunden
int
port
= 1234;
// irgendein freier Port
Socket
socket;
// Socket-Instanz
// ein paar Statusmeldungen
String gestartet = "Socket-Server gestartet...";
String warte
= "... lausche auf Port: " + port + ".";
ServerSocket serversocket = new ServerSocket(port, timeout);
System.out.println(gestartet);
System.out.println(warte);
// ...warten auf eine Client-Anfrage via Socket
while (true) {
socket = serversocket.accept();
// I/O-Streams akzeptieren
try {
PrintWriter
out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
String anfrage = in.readLine();
// Client hat Verbindung aufgenommen
out.println("Anfrage:" + anfrage);
out.flush();
// Verbindung schließen
socket.close();
}
catch (IOException ioex) {
System.err.println("IOException: " + ioex);
}
}
}
}
SocketClient.java
/*
* SocketClient
*
* Einfaches Beispiel für einen Socket-Client
*
* Copyright (c) 1998 by Karsten Brodmann (22.12.1998)
*/
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import SocketClientFrame;
import DlgSocketClient;
21
public class SocketClient extends Applet
{
DlgSocketClient
String
int
Socket
BufferedReader
PrintWriter
ctrls;
host, anfrage, antwort;
port;
socket = null;
in;
out;
// auf Senden-Button reagieren
public boolean action(Event evt, Object objekt)
{
if (objekt.equals("Senden")) {
// prüfen, ob alle Felder ausgefüllt sind...
if ((!ctrls.IDC_SERVER.getText().equals(""))
&& (!ctrls.IDC_PORT.getText().equals(""))
&& (!ctrls.IDC_ANFRAGE.getText().equals(""))) {
host = ctrls.IDC_SERVER.getText();
port = java.lang.Integer.parseInt(
ctrls.IDC_PORT.getText());
anfrage
= ctrls.IDC_ANFRAGE.getText();
// Anfrage via Socket versenden und empfangen
try {
socket = new Socket(host, port);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(
socket.getOutputStream());
// Anfrage senden und Anwort abwarten
out.println(anfrage);
out.flush();
antwort = in.readLine();
ctrls.IDC_ANTWORT.setText(antwort);
}
catch(UnknownHostException uex) {
ctrls.IDC_ANTWORT.setText("unknown host");
}
catch(IOException ioex) {
ctrls.IDC_ANTWORT.setText("IO-Error");
}
}
// ... sonst Aufforderung diese auszufüllen
else
ctrls.IDC_ANTWORT.setText(
"Bitte alle Felder ausfüllen");
return true;
}
// Ereignis wurde nicht behandelt
return false;
}
private Thread
m_SocketClient = null;
// STANDALONE APPLICATION SUPPORT:
//
m_fStandAlone will be set to true if applet is run standalone
//-------------------------------------------------------------------------private boolean m_fStandAlone = false;
public static void main(String args[])
{
SocketClientFrame frame = new SocketClientFrame("SocketClient");
// Must show Frame before we size it so insets() will return valid values
//---------------------------------------------------------------------frame.show();
frame.hide();
frame.resize(frame.insets().left + frame.insets().right + 400,
frame.insets().top + frame.insets().bottom + 200);
SocketClient applet_SocketClient = new SocketClient();
frame.add("Center", applet_SocketClient);
applet_SocketClient.m_fStandAlone = true;
22
applet_SocketClient.init();
applet_SocketClient.start();
frame.show();
}
public SocketClient()
{
}
public String getAppletInfo()
{
return "Name: SocketClient\r\n" +
"Author: Karsten Brodmann\r\n" +
"Created with Microsoft Visual J++ Version 1.1";
}
public void init()
{
//resize(232, 102);
ctrls = new DlgSocketClient (this);
ctrls.CreateControls();
}
public void destroy()
{
}
public void paint(Graphics g)
{
}
}
SocketClientFrame.java
import java.awt.*;
class SocketClientFrame extends Frame
{
public SocketClientFrame(String str)
{
super (str);
}
public boolean handleEvent(Event evt)
{
switch (evt.id)
{
case Event.WINDOW_DESTROY:
dispose();
System.exit(0);
return true;
default:
return super.handleEvent(evt);
}
}
}
DlgSocketClient.java
//-----------------------------------------------------------------------------// DlgSocketClient.java:
//
Implementation for container control initialization class DlgSocketClient
//
// WARNING: Do not modify this file. This file is recreated each time its
//
associated .rct/.res file is sent through the Java Resource Wizard!
//
// This class can be use to create controls within any container, however, the
// following describes how to use this class with an Applet. For addtional
// information on using Java Resource Wizard generated classes, refer to the
// Visual J++ 1.1 documention.
//
// 1) Import this class in the .java file for the Applet that will use it:
23
//
//
import DlgSocketClient;
//
// 2) Create an instance of this class in your Applet's 'init' member, and call
//
CreateControls() through this object:
//
//
DlgSocketClient ctrls = new DlgSocketClient (this);
//
ctrls.CreateControls();
//
// 3) To process events generated from user action on these controls, implement
//
the 'handleEvent' member for your applet:
//
//
public boolean handleEvent (Event evt)
//
{
//
//
}
//
//-----------------------------------------------------------------------------import java.awt.*;
import DialogLayout;
public class DlgSocketClient
{
Container
m_Parent
= null;
boolean
m_fInitialized = false;
DialogLayout m_Layout;
// Control definitions
//-------------------------------------------------------------------------Button
IDSENDEN;
Label
IDC_STATIC1;
Label
IDC_STATIC2;
Label
IDC_STATIC3;
Label
IDC_STATIC4;
TextField
IDC_SERVER;
TextField
IDC_PORT;
TextField
IDC_ANFRAGE;
TextField
IDC_ANTWORT;
// Constructor
//-------------------------------------------------------------------------public DlgSocketClient (Container parent)
{
m_Parent = parent;
}
// Initialization.
//-------------------------------------------------------------------------public boolean CreateControls()
{
// Can only init controls once
//---------------------------------------------------------------------if (m_fInitialized || m_Parent == null)
return false;
// Parent must be a derivation of the Container class
//---------------------------------------------------------------------if (!(m_Parent instanceof Container))
return false;
// Since there is no way to know if a given font is supported from
// platform to platform, we only change the size of the font, and not
// type face name. And, we only change the font if the dialog resource
// specified a font.
//---------------------------------------------------------------------Font OldFnt = m_Parent.getFont();
if (OldFnt != null)
{
Font NewFnt = new Font(OldFnt.getName(), OldFnt.getStyle(), 8);
m_Parent.setFont(NewFnt);
}
// All position and sizes are in Dialog Units, so, we use the
// DialogLayout manager.
//----------------------------------------------------------------------
24
m_Layout = new DialogLayout(m_Parent, 232, 102);
m_Parent.setLayout(m_Layout);
m_Parent.addNotify();
Dimension size
= m_Layout.getDialogSize();
Insets
insets = m_Parent.insets();
m_Parent.resize(insets.left + size.width + insets.right,
insets.top + size.height + insets.bottom);
// Control creation
//---------------------------------------------------------------------IDSENDEN = new Button ("Senden");
m_Parent.add(IDSENDEN);
m_Layout.setShape(IDSENDEN, 169, 81, 50, 14);
IDC_STATIC1 = new Label ("Server:", Label.LEFT);
m_Parent.add(IDC_STATIC1);
m_Layout.setShape(IDC_STATIC1, 13, 7, 29, 8);
IDC_STATIC2 = new Label ("Port:", Label.LEFT);
m_Parent.add(IDC_STATIC2);
m_Layout.setShape(IDC_STATIC2, 13, 23, 16, 8);
IDC_STATIC3 = new Label ("Anfrage:", Label.LEFT);
m_Parent.add(IDC_STATIC3);
m_Layout.setShape(IDC_STATIC3, 13, 39, 28, 8);
IDC_STATIC4 = new Label ("Antwort:", Label.LEFT);
m_Parent.add(IDC_STATIC4);
m_Layout.setShape(IDC_STATIC4, 13, 60, 27, 8);
IDC_SERVER = new TextField ("");
m_Parent.add(IDC_SERVER);
m_Layout.setShape(IDC_SERVER, 53, 7, 65, 14);
IDC_PORT = new TextField ("");
m_Parent.add(IDC_PORT);
m_Layout.setShape(IDC_PORT, 53, 23, 22, 14);
IDC_ANFRAGE = new TextField ("");
m_Parent.add(IDC_ANFRAGE);
m_Layout.setShape(IDC_ANFRAGE, 53, 39, 166, 14);
IDC_ANTWORT = new TextField ("");
m_Parent.add(IDC_ANTWORT);
m_Layout.setShape(IDC_ANTWORT, 53, 60, 166, 14);
IDC_ANTWORT.setEditable(false);
m_fInitialized = true;
return true;
}
}
DialogLayout.java
// This is a part of the Microsoft Visual J++ library.
// Copyright (C) 1996 Microsoft Corporation
// All rights reserved.
import
import
import
import
import
import
import
import
import
//
//
//
//
//
//
//
java.util.Hashtable;
java.awt.LayoutManager;
java.awt.Component;
java.awt.Container;
java.awt.Dimension;
java.awt.Rectangle;
java.awt.FontMetrics;
java.awt.Insets;
java.awt.Label;
class DialogLayout
DialogLayout is a
API calls "dialog
coordinates which
mapping from DLUs
simple layout manager which works with what the Win32
logical units" (DLUs). DLUs are resolution independent
work well for laying out controls on a dialog box. The
to pixels is based on the font in use in the dialog box.
25
//
//
//
//
//
//
//
//
//
//
//
//
//
An x-coordinate DLU is described as 1/4 (.25) of the of the average character
width of the font used in the dialog. A y-coordinate DLU is described as
1/8 (.125) of the character height used in the dialog. One tricky issue to
note: The average character width is not the average of all characters -rather it is the average of all alpha characters both uppercase and
lowercase. That is, it is the extent of the string "a...zA...Z" divided
by 52.
This class allows you to associate a Rectangle (x, y, width, height) with a
Component in a Container. If called upon to layout the container, this
layout manager will layout based on the translation of dialog units to
pixels.
public class DialogLayout
implements LayoutManager
{
protected Hashtable m_map = new Hashtable();
protected int m_width;
protected int m_height;
// DialogLayout methods
public DialogLayout(Container parent, int width, int height)
{
Construct(parent, width, height);
}
public DialogLayout(Container parent, Dimension d)
{
Construct(parent, d.width, d.height);
}
public void setShape(Component comp, int x, int y, int width, int height)
{
m_map.put(comp, new Rectangle(x, y, width, height));
}
public void setShape(Component comp, Rectangle rect)
{
m_map.put(comp, new Rectangle(rect.x, rect.y, rect.width, rect.height));
}
public Rectangle getShape(Component comp)
{
Rectangle rect = (Rectangle)m_map.get(comp);
return new Rectangle(rect.x, rect.y, rect.width, rect.height);
}
public Dimension getDialogSize()
{
return new Dimension(m_width, m_height);
}
// LayoutManager Methods
public void addLayoutComponent(String name, Component comp) { }
public void removeLayoutComponent(Component comp) { }
public Dimension preferredLayoutSize(Container parent)
{
return new Dimension(m_width, m_height);
}
public Dimension minimumLayoutSize(Container parent)
{
return new Dimension(m_width, m_height);
}
public void layoutContainer(Container parent)
{
int count = parent.countComponents();
Rectangle rect = new Rectangle();
int charHeight = getCharHeight(parent);
int charWidth = getCharWidth(parent);
Insets insets = parent.insets();
FontMetrics m = parent.getFontMetrics(parent.getFont());
26
for (int i = 0; i < count; i++)
{
Component c = parent.getComponent(i);
Rectangle r = (Rectangle)m_map.get(c);
if (r != null)
{
rect.x = r.x;
rect.y = r.y;
rect.height = r.height;
rect.width = r.width;
mapRectangle(rect, charWidth, charHeight);
if (c instanceof Label)
{
// Adjusts for space at left of Java labels.
rect.x
-= 12;
rect.width += 12;
}
rect.x += insets.left;
rect.y += insets.top;
c.reshape(rect.x, rect.y, rect.width, rect.height);
}
}
}
// Implementation Helpers
protected void Construct(Container parent, int width, int height)
{
Rectangle rect = new Rectangle(0, 0, width, height);
mapRectangle(rect, getCharWidth(parent), getCharHeight(parent));
m_width = rect.width;
m_height = rect.height;
}
protected int getCharWidth(Container parent)
{
FontMetrics m = parent.getFontMetrics(parent.getFont());
String s
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int
width = m.stringWidth(s) / s.length();
if (width <= 0)
width = 1;
return width;
}
protected int getCharHeight(Container parent)
{
FontMetrics m = parent.getFontMetrics(parent.getFont());
int height = m.getHeight();
return height;
}
protected void
{
rect.x
rect.y
rect.width
rect.height
}
mapRectangle(Rectangle rect, int charWidth, int charHeight)
=
=
=
=
(rect.x
(rect.y
(rect.width
(rect.height
*
*
*
*
charWidth)
charHeight)
charWidth)
charHeight)
/
/
/
/
4;
8;
4;
8;
}
27
Remote Method Innvocation
Das folgende Beispiel verwendet RMI zur Kommunikation zwischen Client und Server. Der Server
lädt eine ihm als Parameter übergebene Datei als „Datenbank“ in den Hauptspeicher. Über den Client kann der Anwender dann eine Suche nach einem Datensatz innerhalb der Datenbank initiieren,
der einem anzugebenden Suchmuster entspricht. Der Server schickt dann den ersten Datensatz,
welcher das Suchmuster enthält, an den Client zurück.
Lookup.java
/*
* Lookup - Interface
*
* Einfaches Beispiel für einen RMI-Server
*
* Copyright (c) 1998 by Karsten Brodmann (22.12.1998)
*/
import java.rmi.*;
public interface Lookup extends Remote {
public String findInfo(String info) throws RemoteException;
}
LookupServer.java
/*
* LookupServer - Interface
*
* Einfaches Beispiel für einen RMI-Server
*
* Copyright (c) 1998 by Karsten Brodmann (22.12.1998)
*/
import
import
import
import
java.io.*;
java.util.*;
java.rmi.*;
java.rmi.server.*;
public class LookupServer extends UnicastRemoteObject
implements Lookup {
private Vector save = new Vector();
public LookupServer(String db) throws RemoteException
{
// einmal "Datenbank" in den Speicher laden
try {
FileReader fr = new FileReader(db);
BufferedReader br = new BufferedReader(fr);
String s = null;
while ((s = br.readLine()) != null)
save.addElement(s);
fr.close();
}
catch (Throwable e) {
System.err.println("exception");
System.exit(1);
}
}
public String findInfo(String info)
{
if (info == null)
return null;
info = info.toLowerCase();
int n = save.size();
for (int i = 0; i < n; i++) {
String dbs = (String)save.elementAt(i);
if (dbs.toLowerCase().indexOf(info) != -1)
return dbs;
}
return null;
28
}
public static void main(String args[])
{
try {
RMISecurityManager security =
new RMISecurityManager();
System.setSecurityManager(security);
String db = args[0];
LookupServer server = new LookupServer(db);
Naming.rebind("LookupServer", server);
System.err.println("LookupServer ready...");
}
catch (Throwable e) {
System.err.println("exception: " + e);
System.exit(1);
}
}
}
LookupClient.java
/*
* LookupClient - Interface
*
* Einfaches Beispiel für einen RMI-Client
*
* Copyright (c) 1998 by Karsten Brodmann (22.12.1998)
*/
import java.rmi.*;
import java.rmi.server.*;
public class LookupClient {
public static void main(String args[])
{
try {
RMISecurityManager security =
new RMISecurityManager();
System.setSecurityManager(security);
String host = "trabant";
String server = "LookupServer";
String name = "rmi://" + host + "/" + server;
Lookup look_obj = (Lookup)Naming.lookup(name);
String results = look_obj.findInfo(args[0]);
if (results == null)
System.err.println("** nicht gefunden **");
else
System.out.println(results);
}
catch (Throwable e) {
System.err.println("exception: " + e);
System.exit(1);
}
}
}
Abenteuer und Freizeit
Der folgende Programmcode zeigt die Implementierung des im Text beschriebenen Prototypen,
„Abenteuer und Freizeit“. Es wird eine 3-stufige Architektur realisiert.
29
Abbildung 13: Screenshot "Abenteuer und Freizeit"
AUFServer.java
/*
* @(#)AUFServer.java 1.0 99/01/07
*
* AUFServer - Schnittstelle zur Realisierung von Datenbankzugriffen
*
für die Beispielanwendung "Abenteuer und Freizeit" im
*
Seminar "Web-Publishing", WS 98/99
*
* Copyright (c) 1999 by Karsten Brodmann
*/
import java.util.*;
/**
* AUFServer stellt die Schnittstelle zur Realisierung von Datenbankzugriffen
* für die Demo-Anwendung "Abenteuer und Freizeit" im Seminar "Web-Publishing"
* im WS 98/99 bei Prof. Dr. O. Vornberger dar.
* <P>
* @version 1.0
* @author Karsten Brodmann
*/
public interface AUFServer extends java.rmi.Remote {
/* Methodenangebot
* --------------*/
/**
* Diese Methode selektiert Umsatzdaten zu den in <i>countries</i> angegebenen
Ländern.
*
* @param usr
- Login des Anwenders
* @param passwd
- Paßwort des Anwenders
* @param countries - Vektor mit Auswahlkriterien für die Selektion
* @return Vector
- Ergebniszeilen, die den Auswahlkriterien entsprechen
* @exception RemoteException - Verbindungsfehler
*/
Vector getAUFInfo(String usr, String passwd, Vector countries)
throws java.rmi.RemoteException;
}
30
AUFServerImp.java
/*
* @(#)AUFServerImp.java 1.0 99/01/07
*
* AUFServerImp - Implementierung des Applikationsservers für die
*
Beispielanwendung "Abenteuer und Freizeit" im
*
Seminar "Web-Publishing", WS 98/99
*
* Copyright (c) 1999 by Karsten Brodmann
*/
import
import
import
import
import
import
import
java.io.*;
java.net.*;
java.util.*;
java.sql.*;
java.rmi.*;
java.rmi.server.UnicastRemoteObject;
java.rmi.registry.LocateRegistry;
class AUFServerImp extends UnicastRemoteObject
implements AUFServer {
AUFServerImp() throws RemoteException {}
/*
* Methode zur Ermitttlung einiger Umsatzdaten anhand
* ausgewählter Länder.
*
* @param user
- Datanbank-Login des Anwenders
* @param passwd
- Paßwort des Anwenders
* @param countries - Vector der in Frage kommenden Länder
* @return Vector
- Liste der Umsatzdaten
*/
public Vector getAUFInfo (String usr,
String pwd,
Vector countries)
throws RemoteException {
// Informationen aus der Datenbank holen.
Vector result = null;
AUFInfoThread aufInfoThread =
new AUFInfoThread(usr, pwd, countries);
// Thread erzeugen und bis zu Ende ablaufen lassen.
Thread auf = new Thread (aufInfoThread);
auf.start();
try {
auf.join();
System.out.println ("Abfrage-Thread laeuft...");
}
catch (java.lang.InterruptedException e){
e.printStackTrace();
}
// Ergebnisse auswerten.
result = aufInfoThread.getResults();
return result;
}
public static void main(String args[]) {
int port = 1099;
System.out.println ("AUF-Server wird gestartet...");
System.setSecurityManager (new RMISecurityManager());
try{
System.out.println ("Starte Server.");
LocateRegistry.createRegistry(port);
System.out.println ("Registry erzeugt...");
AUFServerImp aufs = new AUFServerImp();
System.out.println ("Server-Objekt erzeugt...");
Naming.rebind ("//:1099/AUFServerImpl", aufs);
System.out.println ("Server in der Registry gebunden.");
System.out.println ("Warte auf Anfragen auf Port " + port + "...");
31
}
catch (Exception e) {
System.out.println ("Fehler in AUF-Server" + e);
e.printStackTrace();
}
}
}
AUFInfoThread.java
/*
* @(#)AUFInfoThread.java 1.0 99/01/07
*
* AUFInfoThread - Klasse zur Durchführung von Abfragen in einer
*
Mehrbenutzerumgebung. Je Anfrage wird ein
*
separater Thread erzeugt.
*
*
Beispielanwendung "Abenteuer und Freizeit" im
*
Seminar "Web-Publishing", WS 98/99
*
* Copyright (c) 1999 by Karsten Brodmann
*/
import java.io.*;
import java.sql.*;
import database.DBConnection;
import java.util.*;
class AUFInfoThread implements Runnable {
String usr;
String pwd;
Vector countries;
Vector aufVector;
/*
* Einfacher Konstruktor, erzeugt ein neues Objekt.
*
* @param usr
- Login
* @param pwd
- Paßwort
* @param countries - Liste der gewünschten Länder
*/
public AUFInfoThread(String usr,
String pwd,
Vector countries) {
this.usr = usr;
this.pwd = pwd;
this.countries = countries;
}
/*
* Ueberdefinieren der Standard-run()-Methode.
*/
public void run(){
try
{
// Datenbank-Verbindung herstellen.
DBConnection dbc = new DBConnection("jdbc:odbc:AUF",
usr,
pwd,
"com.ms.jdbc.odbc.JdbcOdbcDriver",
true);
if (dbc.getConnection() != null) {
Enumeration countriesEnum = countries.elements();
String whereClause = " WHERE LAND IN (";
while (countriesEnum.hasMoreElements()) {
whereClause = whereClause + "'" + countriesEnum.nextElement() +
"'";
if (countriesEnum.hasMoreElements()) {
whereClause = whereClause + ",";
}
}
whereClause = whereClause + ")";
// Abfrage vervollständigen und abschicken.
Statement stmnt = dbc.getConnection().createStatement();
ResultSet rs;
32
rs = stmnt.executeQuery ("SELECT * FROM UMSAETZE_JE_LAND_UND_PRODUKT"
+ whereClause);
// Anfrageergebnisse auswerten.
Vector resultVec = handleResult (rs);
this.aufVector = resultVec;
dbc.close();
}
else {
System.out.println ("Benutzer " + usr +
" versuchte erfolglos, eine SQL-Anweisung " +
"auszufuehren.");
}
}
catch (ClassNotFoundException clnfex) {
System.out.println ("Klasse nicht gefunden - CLASSPATH pruefen.");
}
catch (SQLException sqlex) {
System.out.println ("Benutzer " + usr + " hat erfolglos versucht, " +
"eine Datenbank-Verbindung herzustellen.");
}
}
/*
* Auslesen der Anfrageergebnisse
*
* @return Vector - Liste der Umsatzdaten
*/
public Vector getResults (){
return this.aufVector;
}
/*
* Auslesen des ResultSets in einen Vector.
*/
private Vector handleResult (ResultSet rs) {
String recentRow = "";
Vector resVector = new Vector(1,1);
String hersteller;
String modell;
String baujahr;
System.out.println("Werte Resultset aus...");
try {
boolean more = rs.next();
while (more) {
recentRow = recentRow + rs.getString (1) + ", ";
recentRow = recentRow + rs.getString (2) + ", ";
recentRow = recentRow + "U: ";
recentRow = recentRow + rs.getString (3);
recentRow = recentRow + ", K: ";
recentRow = recentRow + rs.getString (4);
resVector.addElement(recentRow);
recentRow = "";
more = rs.next();
}
}
catch (SQLException e){
e.printStackTrace();
}
return resVector;
}
}
AUFApplet.java
/*
* @(#)AUFApplet.java 1.0 99/01/07
*
* AUFApplet - Frontend für Beispielanwendung
*
"Abenteuer und Freizeit" im
*
Seminar "Web-Publishing", WS 98/99
33
*
* Copyright (c) 1999 by Karsten Brodmann
*/
import
import
import
import
import
java.awt.*;
java.util.*;
java.io.*;
java.net.*;
java.rmi.*;
public class AUFApplet extends java.applet.Applet {
AUFServer as = null;
/*
* Standard init() Methode durch SuperCede ueberdefiniert.
*/
public void init() {
SuperCedeInit();
}
/*
* Zurücksetzen aller Komponenten.
*/
protected void removeSelections() {
usrField.setText("");
pwdField.setText("");
int numberOfCountries = countryList.countItems();
for (int i=1;i<=numberOfCountries;i++) {
if (countryList.isSelected(i)) {
countryList.deselect(i);
}
}
resultArea.appendText("Eingabe zurückgesetzt.\n");
}
/*
* Button "Eingabe zurücksetzen" wurde geklickt.
*/
protected void ResetButtonClicked( Event event ) {
// Button 'Eingabe zurücksetzen' geklickt.
// Zuruecksetzen aller Komponenten.
removeSelections();
}
/*
* Button "Anfrage abschicken" wurde geklickt.
*/
protected void OkButtonClicked( Event event )
{
// mind. ein Land ausgewählt?
int numberOfCountryItems = countryList.countItems();
int numberOfSelectedItems = 0;
for (int i=0;i<=numberOfCountryItems;i++) { // 1-0
if (countryList.isSelected(i))
numberOfSelectedItems++;
}
// Vollständigkeit der User-Daten prüfen
if (usrField.getText().equals("") || pwdField.getText().equals(""))
resultArea.appendText ("Bitte Login und Paßwort vollständig " +
"eingeben.\n");
else if (numberOfSelectedItems < 1)
resultArea.appendText ("Bitte mindestens ein " +
"Land auswählen.\n");
else {
// Angaben vollständig => Daten aufbereiten
Vector selectedCountries = new Vector (1,1);
int numberOfCountries = countryList.countItems();
for (int k=0;k<=numberOfCountries;k++) { // 1-0
if(countryList.isSelected(k)) {
34
selectedCountries.addElement(countryList.getItem(k));
}
}
String login = usrField.getText();
String password = pwdField.getText();
// Verbindung zum Server herstellen.
resultArea.setText ("Stelle Verbindung zum Java-DB-Server her. " +
"Bitte etwas Geduld...\n");
try {
// Instanz der Remote-Klasse erzeugen.
as = (AUFServer)Naming.lookup("rmi://" +
getCodeBase().getHost() +
"/AUFServerImpl");
resultArea.setText("Server gefunden, rufe nun Informationen aus " +
"der Datenbank ab...\n");
// Daten vom Server abrufen
Vector queryResult = new Vector (1,1);
queryResult = as.getAUFInfo (login, password, selectedCountries);
//Anfrageergebnisse ausgeben.
resultArea.setText("\n");
Enumeration resEnum = queryResult.elements();
while (resEnum.hasMoreElements()) {
resultArea.appendText(resEnum.nextElement() + "\n");
}
}
catch (Exception e){
resultArea.setText("Fehler:" + e.getMessage() + "\n");
}
}
}
/*
* Überdefinieren einiger Standard-Applet-Methoden.
*/
public boolean handleEvent( Event event ) {
return SuperCedeEvent( event );
}
public void start() {
SuperCedeStart();
}
public void stop() {
SuperCedeStop();
}
/*
* Initialisierung (insbesondere Definition und Konfiguration der
* benutzten GUI-Komponenten.
*/
private final void SuperCedeInit() {
setLayout(null);
setFont( new Font("Helvetica", Font.BOLD, 11));
setBackground(new Color(192, 192, 192));
addNotify();
resize((insets().left + insets().right + 455),
(insets().top + insets().bottom + 459));
label1 = new Label("Authentisierung", Label.LEFT);
label1.setFont( new Font("Helvetica", Font.BOLD, 13));
add(label1);
35
label1.reshape((insets().left + 15),
(insets().top + 9), 186, 16 );
label2 = new Label("Login", Label.LEFT);
add(label2);
label2.reshape((insets().left + 24),
(insets().top + 46), 100, 15);
usrField = new TextField("");
usrField.setEditable(true);
add(usrField);
usrField.reshape((insets().left + 200),
(insets().top + 40), 225, 20);
label3 = new Label("Paßwort", Label.LEFT);
add(label3);
label3.reshape((insets().left + 24),
(insets().top + 78), 100, 15);
pwdField = new TextField("");
pwdField.setEditable(true);
pwdField.setEchoCharacter('*');
add(pwdField);
pwdField.reshape((insets().left + 200),
(insets().top + 72), 225, 20);
label5 = new Label("Länder (Mehrfachauswahl möglich)",
Label.LEFT);
label5.setFont(new Font("Helvetica", Font.BOLD, 13));
add(label5);
label5.reshape((insets().left + 15),
(insets().top + 113), 410, 16);
// nicht gerade datengetrieben ;-(
countryList = new List(2, true);
// countryList.addItem("Alle");
countryList.addItem("Australien");
countryList.addItem("Belgien");
countryList.addItem("Deutschland");
countryList.addItem("Frankreich");
countryList.addItem("Großbritannien");
countryList.addItem("Hongkong");
countryList.addItem("Japan");
countryList.addItem("Kanada");
countryList.addItem("Mexiko");
countryList.addItem("Schweden");
countryList.addItem("Singapur");
countryList.addItem("Spanien");
countryList.addItem("USA");
add( countryList);
countryList.reshape((insets().left + 24),
(insets().top + 148), 401, 61);
okButton = new Button("Anfrage abschicken");
add(okButton);
okButton.reshape((insets().left + 24),
(insets().top + 230), 177, 20);
resetButton = new Button("Eingabe zurücksetzen");
add(resetButton);
resetButton.reshape((insets().left + 248),
(insets().top + 230), 177, 20);
label6 = new Label("Suchergebnis", Label.LEFT);
label6.setFont(new Font( "Helvetica", Font.BOLD, 13));
add(label6);
label6.reshape((insets().left + 15),
(insets().top + 270), 410, 16);
resultArea = new TextArea("");
resultArea.setEditable(false);
add(resultArea);
resultArea.reshape((insets().left + 15),
(insets().top + 290), 410, 145);
super.init();
}
36
/*
* Allgemeine Festlegungen des Event-Handling.
*/
private final boolean SuperCedeEvent( Event event ) {
if ((event.target == okButton) && (event.id == Event.ACTION_EVENT)) {
OkButtonClicked( event );
return true;
}
if ((event.target == resetButton) && (event.id == Event.ACTION_EVENT)) {
ResetButtonClicked( event );
return true;
}
return super.handleEvent( event );
}
/*
* Start-Methode und Stop-Methode des AWT-Generators.
*/
private final void SuperCedeStart() {}
private final void SuperCedeStop()
{}
/*
* Allgemeine Deklarationen.
*/
CheckboxGroup filialSelect;
Label label1;
Label label2;
TextField usrField;
Label label3;
TextField pwdField;
Label label5;
List countryList;
Button okButton;
Button resetButton;
Label label6;
TextArea resultArea;
}
37
Konventielles Data-Warehouse-Frontend
Die hier abgenildete Applikation wurde mit PowerPlay von Cognos, Inc. erstellt.
Abbildung 14: Konventielles Frontend zu "Abenteuer und Freizeit"
38
Herunterladen