WISSEN : Datenbankzugriff http://automate.informatik.tu-muenchen.de/whitepapers/ix1198/ Transparenter Zugriff auf ODBMS über CORBA Schnelle Schichten Klaus Bergner, Karsten Kuhla, Andreas Rausch Die Entwicklung von Client/Server-Anwendungen ist nicht einfach - im Gegensatz zum Big Mac bekommt man eine mehrschichtige Architektur nicht auf Bestellung. AutoMate will Abhilfe schaffen. Unterthema: iX-TRACT Unterthema: Listing Große Anwendungen basieren oft auf 3-Schichten-Architekturen. Während sie bei Bank- oder Buchungssystemen meist noch nicht auf objektorientierten Techniken aufbauen, führt vor allem bei der Entwicklung neuer Anwendungen kaum ein Weg daran vorbei: Verteilte CASE- oder CAD-Werkzeuge und moderne Telekommunikationssysteme beispielsweise können auf dieser Grundlage durchgängig entwickelt werden. Programmierer erhalten bei der Fertigstellung der Komponenten in den einzelnen Schichten bereits gute Unterstützung. Auf der unteren tummeln sich viele ausgereifte und immer stärker standardisierte objektorientierte Datenbanksysteme (ODBMS). Im Vergleich zu ihren relationalen Verwandten (RDBMS) versprechen sie einen nahtlosen Übergang zur objektorientierten Programmierung bei gleicher Stabilität und Performance. Heutige ODBMS können nicht nur Daten speichern und zurückliefern, sondern bieten alle nötigen Zusatzdienste, etwa Transaktionsmanagement. Objektorientierte Sprachen wie Java, grafische Werkzeuge und wiederverwendbare Standardkomponenten erleichtern die Entwicklung der Anwendungsserver und der Clients in den beiden oberen Schichten. Als Middleware gewährleisten CORBA-basierte Object Request Broker 1 of 8 01.04.99 00:06 WISSEN : Datenbankzugriff http://automate.informatik.tu-muenchen.de/whitepapers/ix1198/ (ORB) und DCOM die Kommunikation zwischen den Komponenten verschiedener Schichten oder auch innerhalb einer einzelnen. Methodenaufrufe leitet der ORB für den Programmierer transparent über Prozeß- und Rechnergrenzen bis zum aufgerufenen Objekt weiter. Leistungsstarke, sprach- und plattformübergreifende Systeme sind kommerziell verfügbar [1]. Trotz alledem ist es immer noch schwierig, ein dreischichtiges System zu realisieren. Bevor Entwickler transparent auf persistente Java-Objekte in einer Datenbank zugreifen können, will erst das Zusammenspiel von ODBMS, ORB und Java Virtual Machine organisiert sein. Standardlösungen dafür gab es bisher nicht, obwohl OMG und ODMG sowie ORB- und ODBMS-Hersteller bereits vor Monaten CORBA-ODBMS angekündigt haben [2]. Kompliziertes Zusammenspiel Wer seine Architektur auf CORBA und einem Java-ODBMS aufbauen wollte, mußte sich bisher selbst eine aufwendige Speziallösung zusammenbasteln. Problematisch dabei ist, daß man zwei Objektmodelle entwickeln, warten und dokumentieren muß: eines für die CORBA- und ein anderes für die persistenten ODBMS-Objekte. Die Grenzen solcher proprietären Lösungen zeigen sich meist schnell und machen ein kostenintensives Reengineering unumgänglich. AutoMate soll den Programmierer von diesen Problemen befreien. Entwickelt wurde es am Lehrstuhl Broy des Instituts für Informatik der Technischen Universität München im Rahmen des Bayerischen Forschungsverbunds Software-Engineering (FORSOFT). Die Software besteht aus zwei Teilen: einem Generator für das Objektmodell der CORBA-Objektdatenbank und einigen Management- und Verwaltungskomponenten in der Applikationsschicht des Servers. Ausgangspunkt für den Generator ist ein UML-Klassendiagramm, das mit Hilfe des CASE-Tools Rational Rose entwickelt werden kann. Bei der Modellierung stehen alle üblichen Gestaltungsmittel der Objektorientierung zur Verfügung: Neben Klassen mit ihren Attributen kann man beispielsweise Assoziations- und Vererbungsbeziehungen zeichnen. Ein weiteres nützliches Konstrukt, welches in Rose und Java standardmäßig nicht vorgesehen ist, sind Aufzählungstypen. Sie lassen sich im Klassendiagramm als Klassen mit dem UML-Stereotyp Enum anlegen. Weiterhin kann der Entwickler mit Hilfe spezieller Tags in Rose spezifizieren, welche Attribute der spezifizierten Klassen persistent sein sollen. Damit ist die ‘Programmierung’der Applikations- und der Datenhaltungsschicht bereits abgeschlossen. Der in Rational Rose integrierte AutoMate-Generator erzeugt aus dem Klassendiagramm den Code für eine lauffähige CORBA-Objektdatenbank und startet die Basiskomponenten: den IONA-ORB-OrbixWeb und das ODBMS-Versant (über andere Kombinationen denkt man nach). Der ganze Vorgang dauert auf einem durchschnittlichen PC keine 10 Minuten. Damit die Clients in der Präsentationsschicht auf die gespeicherten CORBA-Objekte zugreifen können, bietet AutoMate neben dem Generator noch Management- und Verwaltungskomponenten für den Server. Sie sind wie die gespeicherten Objekte über CORBA zugänglich und haben beispielsweise Schnittstellen für das Erzeugen und Löschen von Objekten, das Management von Transaktionen und das Absetzen von Abfragen (siehe Abbildung 1) Generiert: CAD in zehn Minuten Ein kleines Anwendungsbeispiel soll illustrieren, wie einfach etwa die Programmierung eines verteilten CAD-Tools sein kann. Auf der Serverseite steht zunächst der Entwurf des Klassendiagramms für die Objektdatenbank an. Abbildung 2 zeigt einen Ausschnitt eines möglichen Objektmodells mit den Klassen Car, Wheel und Clutch zur Repräsentation eines Autos mit zugehörigen Rädern und Anhängerkupplung. Aus diesem Diagramm kann AutoMate den 2 of 8 01.04.99 00:06 WISSEN : Datenbankzugriff http://automate.informatik.tu-muenchen.de/whitepapers/ix1198/ Anwendungsserver erzeugen. Neben der Möglichkeit, eine 3-Schichten-Architektur zu entwickeln, liefert AutoMate Verwaltungskomponenten in der Applikationsschicht (Abb. 1). Wie der Programmierer nach der Generierung auf entfernte Datenbankobjekte zugreifen kann, ist im Listing zu sehen. Angenommen, der Designer des in der Datenbank gespeicherten Automodells ‘Donatas 2000 GLX’möchte in seinem CAD-System dieses Auto mit breiteren Reifen und einer Anhängerkupplung versehen. Der Client des CAD-Systems muß dazu zuerst die CORBA-Schnittstelle initialisieren, bevor er sich Zugriff auf das erste CORBA-Objekt verschaffen kann, den sogenannten ReceptionManager. Managerobjekte sind Singletons - im laufenden System gibt es jeweils nur eine Instanz von ihnen. Sie stellen allgemeine Dienste zur Verfügung, die sich nicht einem einzelnen Anwendungsobjekt zuordnen lassen. Der ReceptionManager dient als eine Art Empfangschef, an den sich die Clients wenden können, um an andere Manager weitervermittelt zu werden (in diesem Fall TransactionManager, ObjectManager und NamingManager). 3 of 8 01.04.99 00:06 WISSEN : Datenbankzugriff http://automate.informatik.tu-muenchen.de/whitepapers/ix1198/ Aus diesem Ausschnitt aus dem Klassendiagramm eines CAD-Tools kann das Werkzeug Applikations- und Datenhaltungsschicht generieren (Abb. 2). Über den TransactionManager kann der Client ein Transaktionsobjekt erzeugen und starten. Analog zu einer Datenbank repräsentiert dieses Objekt den Transaktionskontext des Clients gegenüber dem Server. Es besitzt folglich die klassischen Methoden einer Datenbanktransaktion: begin, commit und abort. Jeder Methodenaufruf muß innerhalb des Transaktionskontexts ablaufen, damit das CORBA-Objekt die aufgerufenen Methoden der richtigen Datenbanktransaktion zuzuordnen weiß. Insbesondere Multithreaded-Clients müssen gleichzeitig mehrere Transaktionen durchführen können. AutoMate kann deshalb jedes Objekt gezielt in einen Transaktionskontext einsetzen, bevor es für den Client verfügbar wird. Dies ist beispielsweise der Fall, wenn sich der Client über den Naming- oder den QueryManager Referenzen auf in der Datenbank gespeicherte Objekte besorgt, oder beim Erzeugen eines neuen persistenten Objektes mit Hilfe des ObjectManager. Komplexes im Hintergrund Die Navigation über persistente Objekte unterscheidet sich nicht von der über lokale. Sowohl der Zugriff auf Attribute und Objekte als auch die Iteration über assoziierte beziehungsweise aggregierte Objekte ist transparent. Für jede 1-zu-n-Beziehung kann der Client dabei eine Methode aufrufen, die ihm eine Java-Enumeration liefert. Alle nötigen Enumerations generiert AutoMate automatisch als CORBA-Objekte. Sie stellen die üblichen Iterierungsmethoden hasMoreElements und nextElement zur Verfügung, über die sich die Referenzen zu den Objekten am anderen Ende der Assoziation gewinnen lassen. Obwohl die Generierung des Servers aus einem Klassendiagramm für den Programmierer sehr einfach erscheint, laufen hinter den Kulissen komplexe Vorgänge ab. Der AutoMate-Generator erzeugt zunächst die IDL-Dateien (Interface Definition Language) für die Anwendungsschicht. Sie beschreiben die für den Client sichtbare Schnittstelle und können von einem IDL-Compiler in die für CORBA nötigen Stub- und Skeleton-Klassen übersetzt werden. Daneben generiert AutoMate den Java-Code für den Server. Er besteht im wesentlichen aus Klassen für die ODBMS- und die CORBA-Objekte mit dem Code für die Verbindung zwischen den beiden Welten. Die Realisierung der Anbindung erfolgte gemäß dem Delegationsansatz [3]. Hier sind die Datenbankobjekte nicht selbst für die Kommunikation mit dem Client zuständig - diese Aufgabe übernehmen die ihnen vorgeschalteten TIE-Objekte. Sie fungieren als CORBA-Skeletons und nehmen die Aufrufe des zugehörigen Stub auf dem Client entgegen, um sie dann an das entsprechende persistente Datenbankobjekt weiterzureichen. Die Verwendung von TIE-Objekten hat den Vorteil, daß das persistente Objekt nicht von der Skeleton-Klasse erben muß. Gerade bei der Implementierung in Java ist dies essentiell, weil diese Sprache keine Mehrfachvererbung bietet. Die eine vorhandene Vererbungsmöglichkeit wird damit nicht bereits durch die Infrastruktur aufgebraucht. Nachteil der TIE-Objekte: ihre Erzeugung ist speicherintensiv und aufwendig. Bei der Implementierung muß man deshalb darauf achten, daß sie sich nicht unnötig vermehren. AutoMate stellt dazu beispielsweise sicher, daß in der gleichen Transaktion nicht mehrere TIE-Objekte für dasselbe Datenbankobjekt entstehen. Heimlich eingeschleuster Code In Abbildung 3 ist zu sehen, welche Klassen und Interfaces in der Implementierung insgesamt für die Klasse Car aus dem Rose-Klassendiagramm erzeugt werden: Das Interface Car definiert die 4 of 8 01.04.99 00:06 WISSEN : Datenbankzugriff http://automate.informatik.tu-muenchen.de/whitepapers/ix1198/ Client-Schnittstelle der für den Programmierer normalerweise unsichtbaren Stub-Klasse _CarStub. Auf dem Server wird es von der TIE-Klasse _tie_Car implementiert, die von der CORBA-Skeleton-Klasse _CarSkeleton abgeleitet ist. Die persistente Klasse CarImplPers enthält zwar die gleichen Operationen wie Stub- und TIE-Klasse, implementiert aber im Gegensatz zu diesen nicht das Car-Interface, sondern ein zu diesem äquivalentes namens _CarOperations. Damit sind CORBA- und Datenbankobjekte von ihren Typen her klar getrennt. Diese Klassen und Interfaces werden aus dem Klassendiagramm für die Klasse Car erzeugt (Abb. 3). Ist der gesamte Code generiert, läßt sich der Servercode mit einem Java-Compiler in Bytecode übersetzen. Danach muß der Programmierer noch die Klassen der persistenten Objekte (beispielsweise CarImplPers) ODBMS-tauglich machen. Letzteres geschieht mit einem von Versant gelieferten Enhancer-Programm. Es modifiziert den Bytecode und verwandelt Zugriffe auf persistente Attribute in Zugriffe auf die Datenbank. Dieses Vorgehen ist ähnlich wie bei Makros für statisches SQL, die den Code für den Datenbankzugriff gewissermaßen ‘dazuschmuggeln’. Nach diesem abschließenden Schritt sind Anwendungsschicht und Datenhaltungsschicht vollständig realisiert und lassen sich als Server im Netz starten. Das Szenario aus Abbildung 4 zeigt die Rollen und das Verhalten der Objekte im laufenden System. Beim Aufruf der Methode setClutch auf dem Client leitet der gerufene Stub den Aufruf zunächst über das Netz zu dem entsprechenden TIE-Objekt weiter. Für jeden Parameter (hier nur das clutch-Objekt) muß dann zu dem übertragenen Stub das jeweilige TIE-Objekt gefunden werden. Daraufhin ruft das TIE-Objekt das persistente ImplPers-Objekt und delegiert den Aufruf dorthin weiter. Nach einer letzten Umsetzung des Parameters von einem TIE-Objekt in ein Datenbankobjekt mittels der Methode _deref kann schließlich die Methode auf dem persistenten Objekt ausgeführt werden. 5 of 8 01.04.99 00:06 WISSEN : Datenbankzugriff http://automate.informatik.tu-muenchen.de/whitepapers/ix1198/ Die Rollen und das Zusammenspiel der Objekte im laufenden System - über das TIE-Objekt wird der Aufruf zum Implementierungsobjekt weitergereicht (Abb. 4). AutoMate ist in der jetzigen Form bereits eine tragfähige Grundlage für die Entwicklung performanter 3-Schichten-Architekturen. Die durchschnitliche Zeit für einen Serverdatenzugriff, bei dem sich das Objekt bereits im Cache befindet, liegt zwischen 10 und 20 ms (gemessen auf einem 100-MBit/s-Netz, Client und Server jeweils 200-MHz-Pentium-II mit JDK 1.1.6). Entwicklung noch nicht am Ende Die Architektur läßt sich vielfältig erweitern und optimieren. Einfach durchzuführen ist beispielsweise das Hinzufügen von Queries - im wesentlichen muß hier nur eine schon in der Datenbank vorhandene Schnittstelle weiter nach oben durchgereicht werden. Schwieriger ist, Funktionen wie Schemaevolution und Versionierung von Objekten und Schemas zu realisieren. Hier bietet CORBA mit dem Interface Repository bereits eine Schnittstelle an, die sich eventuell in die Lösung integrieren ließe. Als einer der nächsten Schritte zur Optimierung ist geplant, den Generator so zu erweitern, daß Java-Methoden direkt von den CORBA-Objekten auf der zweiten Schicht ausgeführt werden. Das hat den Vorteil, daß sich bei einigen Anwendungen die Kommunikation zwischen Clients und Anwendungsservern wesentlich verringert, da die Datenzugriffe innerhalb solcher Methoden rein auf der Ebene der CORBA-Objekte erfolgen. Weitere Optimierungen sind möglich, wenn Datenbanken erst eine integrierte virtuelle Java-Maschine enthalten: Methoden können dann auf der Datenbankschicht ablaufen. Das verringert nicht nur die Kommunikation zwischen Anwendungsservern und Datenbankschicht, sondern erlaubt dem ODBMS zusätzliche Verbesserungen, da etwa die Verwaltung der Sperren lokal stattfinden kann. Zudem sinkt die Anzahl der CORBA-Objekte, da der Client manche gerufenen Objekte gar nicht mehr kennen muß. Anstatt die Ausführung von Methoden in tiefere Schichten zu verlegen, kann man auch den umgekehrten Weg wählen und die Daten teilweise auf den Client verlagern. Eine für den Programmierer transparente Möglichkeit ist dabei das Caching von Daten auf dem Client. Um die Cache-Konsistenz sicherzustellen und Sperren korrekt zu verwalten, sind unterschiedliche Möglichkeiten denkbar - ein einfacher Write-Through-Cache für die Clients sollte im Generator 6 of 8 01.04.99 00:06 WISSEN : Datenbankzugriff http://automate.informatik.tu-muenchen.de/whitepapers/ix1198/ schnell realisierbar sein. Die angesprochenen Optimierungsvarianten erlauben es, die Verteilung von Daten und Funktionen beim Entwurf eines Systems erheblich zu beeinflussen. Java bietet außerdem die Perspektive, daß sich Änderungen zukünftig auch zur Laufzeit eines Systems durchführen lassen. Wenn die Migration von Objekten zwischen Datenbanken realisiert wird, erhält der Entwickler ein flexibles System, das er einfach um Mechanismen zur Lastbalancierung erweitern kann und das eine gute Basis für mobile Anwendungen bietet. Eine Evaluierungsversion von AutoMate ist erhältlich unter http://automate.informatik.tu-muenchen.de. Das System ist auf der Systems ’98 am Gemeinschaftsstand Bayern Innovativ (Halle A5, Stand 221-230) zu besichtigen. (jd) Dr. Klaus Bergner Andreas Rausch forschen am Lehrstuhl Broy der TU München im Bereich der komponentenorientierten Softwareentwicklung. Karsten Kuhla studiert an der TU München Informatik und war maßgeblich an der Entwicklung von AutoMate beteiligt. Literatur [1] Peter Averkamp, Arno Puder, Kay Römer, Kersten Auel; ORBs; Urbi et ORBi; Von Big Blue bis GPL: Object Request Broker; iX11/98, S. 74 ff. [2] Cosima Schmauch, Bernd Waibel; Warten auf den ‘Object Database Adapter’; OBJEKTspektrum 1/98, S. 55 ff. [3] Object Management Group; The Common Object Request Broker; Architecture and Specification 1995 Kasten 1 iX-TRACT AutoMate kann aus Rational-Rose-Klassendiagrammen 3-Schichten-Architekturen generieren. Zielarchitektur ist eine Kombination aus ODBMS und CORBA-ORB. Funktionsumfang und Performance der aktuellen Version sind für viele Zwecke bereits ausreichend, es gibt viele Optimierungsmöglichkeiten. Kasten 2 Listing Nach der Erzeugung des Anwendungsservers kann der Entwickler auf entfernte 7 of 8 01.04.99 00:06 WISSEN : Datenbankzugriff http://automate.informatik.tu-muenchen.de/whitepapers/ix1198/ Datenbankobjekte zugreifen. // initialize the ORB ORB orb = ORB.init(); // get a CORBA reference to the reception of the AutoMate system ReceptionManager reception = ReceptionManagerHelper.bind( "AutoMateReceptionManager", "automate.tum.de"); // get CORBA references to the managers TransactionManager transactionManager = reception.getTransactionManager(); ObjectManager objectManager = reception.getObjectManager(); NamingManager namingManager = reception.getNamingManager(); // create and start a new transaction on the car database Transaction transaction = transactionManager.open( "cars", Locking.READ_WRITE, TransactionLogic.PESSIMISTIC); transaction.begin(); // get a CORBA reference to the database object named "Donatas 2000 GLX" Car carModel = CarHelper.narrow( namingManager.lookup(transaction, "Donatas 2000 GLX")); // set the size of all wheels to 5 WheelEnumeration wheels = carModel.getWheels(); while (wheels.hasMoreElements()) wheels.nextElement().setSize(5); // create a new persistent Clutch object Clutch clutch = ClutchHelper.narrow( objectManager.create(transaction, "de.tum.automate.cars.Clutch")); // add the created clutch to the car model carModel.setClutch(clutch); // commit and destroy the transaction transaction.commit(); transactionManager.close(transaction); 8 of 8 01.04.99 00:06