Probleme und Lösungen der Plattform - unabhängigen Entwicklung am Beispiel einer Software für Identity - Management Als Vorlesung gehalten an der TU Dresden am 13.4.2007 Im Rahmen der Ringvorlesung „Softwareentwicklung in der industriellen Praxis“ Lehrstuhl Softwaretechnologie Frau Dr. Birgit Demuth Autoren: Dipl.-Ing Ingo Rohner Absolvent 1985 an der TU Dresden, Studienrichtung Informationsverarbeitung. Dipl.-Inf. (FH) Jörg Rosenkranz Absolvent 1998 an der HTW in Dresden, Studienrichtung Informatik Die Firma Völcker Informatik AG (VI) hat ihren Sitz in Berlin. Die Autoren arbeiten in der Niederlassung Dresden als Softwareentwickler und sind hauptsächlich mit dem Produkt ActiveEntry beschäftigt. Alle Angaben im Vortrag beziehen sich auf dieses Produkt. Prämissen: a) Die Firma und das Entwicklerteam sind relativ klein, das Produkt ist relativ groß b) die Kunden haben Freiheiten hinsichtlich - des eingesetzten Betriebssystems - der verwendeten Datenbank - der verwendeten Anzeigetechnologie (Fat-Client / Browser) - der Anpassung der Software auf ihre speziellen Gegebenheiten Um diesen Widerspruch aufzulösen, definieren wir das Prinzip Highlander: "Es kann nur einen (Code) geben" Inhalt 1) Die Firma................................................................................................................ 3 2) heutiges Arbeitsgebiet von VI................................................................................. 6 2.1 Compliance ....................................................................................................... 6 2.2) Was ist Identity - Management ........................................................................ 7 2.3) Provisioning ..................................................................................................... 8 2.4 Betriebsdatenabbildung .................................................................................... 9 3. Lösungsansätze für IdM, Provisioning und ComplianceCheck ............................. 10 3.1 Lösungsansätze der Marktführer .................................................................... 10 3.2 Lösungsansatz von VI..................................................................................... 11 3.2.1 Vorgehensweise von VI im Projekt ........................................................... 14 4) Plattform- unabhängige Implementierung............................................................. 15 4.1 die Voraussetzungen bei VI ............................................................................ 15 4.2 die Kundenforderungen................................................................................... 16 4.3 die Lösungswege ............................................................................................ 17 5) Konkrete Implementierung der Ebenen ............................................................... 17 5.1 Die Businesslogik / Objekt-Ebene ................................................................... 17 5.2 ) Datenbank-Ebene ......................................................................................... 18 5.2.1. Generierung und Single Source .............................................................. 19 5.2.2. liebevolle Handarbeit ............................................................................... 22 5.2.3. SQL-Formatter......................................................................................... 23 5.3. Frontend – Ebene .......................................................................................... 25 1) Die Firma Mit einem kleinen Rückblick in die Geschichte wollen wir zeigen, wie sich die Firma und das Produkt entwickelt haben und wie wir zu unseren heutigen Themen im Identity - Management kamen, ja eigentlich zwangsläufig kommen mußten. In den Jahren 1992 / 1993 haben die späteren Gründer bei der Krone Netzwerkservice GmbH zusammengearbeitet. 1994 wurde die Firma gegründet, erst als GbR, später als GmbH. Seit 1999 ist Völcker Informatik AG eine Aktiengesellschaft. Zur Gründung der Firma 1994 war der Stand der Technik auf dem Arbeitsplatz Windows 3.11, im Serverbereich Novell Netware in den Versionen 2.x, 3.11, 3.12 und die Herausforderung hieß, 200 PCs in einem Netz zum Laufen zu bringen. 200 PCs – eine Herausforderung? Da lächeln Sie inzwischen drüber, mit den damaligen Mittel war das jedoch nicht trivial zu realisieren. Insbesondere ging es in der Anfangszeit von VI um den Aufgabenbereich Unattended Setup, das heißt um die Fragen: - Wie bekomme ich Stückzahlen von PCs an die Arbeitsplätze? - Wie bekommen die PCs ihr Betriebssystem? - Wie bekommen die PCs bzw. die Anwender ihre Applikationen? Insbesondere der letzte Punkt führte uns zum Thema der automatischen Softwareinstallation, d.h. wie bekommt jeder PC genau die Software und die Treiber, die ihm zugedacht sind. Bei Windows 3.11 wurde dies realisiert über liebevolles Patchen der Dateien Win.Ini und System.Ini. Es wurden Skripte gebaut, um die INIDateien zu modifizieren, um dann die Netze auszurollen. Im Jahr 1996 haben wir unser erstes Netz auf Basis von NT 3.51 bei den Berliner Verkehrsbetrieben gebaut. Damit erreichten wir erstmal die Größenordnung von 3000 Benutzern. NT 3.51 war die Software der Server, teilweise auch der Clients, meistens hatten wir jedoch Windows 95 Clients. Dort wurde erstmalig ein Verfahren angewendet, die Software anhand von Gruppenmitgliedschaften der Nutzer zu verteilen. Wir hatten ein eigenes Verfahren für Softwareverteilung entwickelt. Das Verfahren beruht auf einem Delta-Abbild und ist eigentlich eine relativ triviale Sache, das machen heutzutage viele. Die Idee war ursprünglich auch nicht ganz von uns. Grob umrissen funktioniert das Verfahren wie folgt: Wir haben am Anfang einen PC, der jungfräulich mit dem Betriebssystem aufgesetzt ist. Von diesem PC merken wir uns alle Eigenschaften, alle Dateien, Registry-Einträge, Ini-File-Einträge, Desktopsymbole und Menüsymbole. Anschließend installieren wir die Applikation oder den Treiber auf dem PC und konfigurieren alle Einstellungen so, wie sie gewünscht werden. Bei Office z.B. betrifft diese Konfiguration die Menüs, die Vorlagenverzeichnisse oder die Rechtschreibkontrolle. Von der so entstandenen PCKonfiguration merken wir uns wiederum alle Eigenschaften. Aus den gemerkten Zuständen wird ein Delta gebildet, welches wir ein Profil nennen. Völcker Informatik AG hat in diesem Zusammenhang ein Werkzeug entwickelt, welches dieses Profil in eine Maschine schreiben und es auch spurlos wieder löschen kann. Damit hatten wir einen Mechanismus für eine sehr schnelle Softwareinstallation. Die Deltabildung läuft im Allgemeinen um die 90 Sekunden für eine kompletten PC. Bei der eigentlichen Softwareinstallation wird die meiste Zeit dafür benötigt, die Profile durch das Netz zu transportieren, weswegen wir inzwischen an dieser Stelle einen asynchron arbeitenden Cache verwenden. Für die Zuordnung der Software haben wir nicht die Maschinen sondern die NTKonten verwendet, die Software also den Nutzern zugeordnet. Der Nutzer ist Mitglied in einer Gruppe, welche als Applikationsgruppe gekennzeichnet ist. Unser Werkzeug schaut nach, welcher Nutzer welchen Gruppen angehört und demzufolge werden die zugehörigen Applikationen installiert oder deinstalliert. Im Projekt bei den Berliner Verkehrsbetrieben haben wir innerhalb von 3 Wochen die 3000 PCs einmal komplett ausgerollt. Dazu kamen ein paar Roadies, welche die Kisten an die Plätze gebracht, ausgepackt, aufgestellt und Kabel angesteckt haben, die MAC-ID per Telefon durchgesagt haben, Knöpfchen gedrückt haben und dann fuhr der PC hoch. Das war für beide Seiten ein sehr erfolgreiches Projekt, welches uns den Weg geebnet hat für viele weitere Entwicklungen. Im den Jahren 1997/1998 haben wir dann das erste NT 4 Projekt realisiert bei der Schering AG. Bei diesem Kunden handelte es sich bereits um 10000 Nutzer. In diesem Projekt haben wir zum ersten Mal das Prinzip der Vererbung über Betriebsdaten angewendet. Der Kundenwunsch war, daß ein Mitarbeiter bzw. sein NT4-Konto über seine Mitgliedschaft in Abteilungen, Kostenstellen oder Standorten Applikationen und Gruppen erben soll. Das klingt erst mal ganz einfach – ist es letztendlich auch, wenn man ein paar unbedingt notwendige Randbedingungen einhält. Wir haben damals auch das erste Mal eine komplette Vollsynchronisation eines Zielsystems implementiert. Es wurden die kompletten Informationen zu den NT4Domänen vollständig in unsere Datenbank eingelesen, d.h. alle Informationen zu den Konten, Gruppen und Mitgliedschaften. In der Datenbank wurden die Zuweisungen der Nutzer vorgenommen und die Ergebnisse, die aufgrund von Strukturveränderungen oder auch Direktzuweisungen entstanden sind dann wieder in die Umgebung publiziert. Im Jahr 1999 haben wir das Konzept der Betriebsdatenabbildung auf Wunsch eines weiteren Kunden weiter ausgebaut. Dr. Eckhardt Knauer war damals EDV-Leiter bei der AOK in Berlin. Er sagte uns: „Ich als EDV-Mensch bin immer der Letzte in der Firma, der von irgendwelchen Einstellungen oder Entlassungen erfährt. Und ich bin auch der Letzte in der Firma, der erfährt, daß ein PC irgendwo abgebaut und woanders wieder angeschlossen wurde oder daß ein Monitor irgendwo umgesetzt worden ist. Ich weiß eigentlich fast nichts. Das Einzige, was ich weiß, ist, da steht ein Schreibtisch, für den eine Arbeitsaufgabe definiert ist“. Also haben wir den Schreibtisch in unserer Datenbank modelliert. Auf dem Schreibtisch stellen wir einen PC auf und schließen einen Drucker an. So ist das Prinzip der Arbeitsplätze bei uns entstanden. Das hat uns dann in späteren Projekten des Öfteren gerettet. Im Jahr 2001 folgte die Integration von ActiveDirectory-Systemen, auch wieder komplett per Vollsynchronisation. Zu der Zeit hatten wir erstmals das Konzept der Person eingeführt, ein ähnliches Abstraktum wie den Arbeitsplatz. Anfänglich hatten wir nur ein einziges Zielsystem angeschlossen, das war entweder NT 4 mit einer oder mehreren Domänen bzw. Active Directory. Es war von einigen unserer Kunden gewünscht, daß diese einen Überblick bekommen, wenn eine Person 2 Konten besitzt. 99% aller Nutzer haben in einem Zielsystem genau ein Konto. Aber es gibt ein paar wenige, die haben noch ein Extrakonto für administrative Aufgaben. Diese Abbildung konnten wir vorher noch nicht leisten. Da galt für uns (wie heute immer noch für viele Anbieter): Eine Person = ein Konto. Kurz danach kamen weitere Zielsysteme in unser Produkt, so z.B. Lotus Notes und Novell NDS, damit war die Zusammenführung diverser Konten in verschiedenen Systemen auf Personen dringend geboten. Im Jahr 2003 begannen wir ein Projekt in der Landeshauptstadt München mit 160000 Nutzern im Netz. Bei diesen Nutzer handelt es sich um alle Schüler von der 1. bis zur 13. Klasse, alle Berufsschüler und sämtliches Verwaltungspersonal im Pädagogikbereich der Stadt München. Alle diese Nutzer bekamen ein Konto, ein Postfach, ein Home-Verzeichnis und Ablageverzeichnisse. Die Verwendung bestimmter Betriebssysteme war zu der Zeit in München ein Politikum, das dazu führte, daß ausschließlich NICHT- Microsoft-Produkte zu verwenden waren. Wenn wir uns im Gegensatz dazu die bisherige Geschichte von Völcker Informatik AG dazu ansehen: – Völcker Informatik AG war „deutlich blau gefärbt“, alles war Microsoft-geprägt – Linux – man weiß wie man es schreibt, man hat es schon mal gehört, schon mal gesehen – aber dafür programmieren? – Oracle – ja, das soll wohl auch eine Datenbank sein. Wir haben bis dahin mit Microsoft SQL-Server gearbeitet, alle Versionen von der 6.5 an Wir nutzten die gebotene Chance und reimplementierten unsere gesamte Software. 2001 hatte Microsoft .NET vorgestellt, aus unserer Sicht das bessere JAVA. Miguel d Icasa sah das genauso und begründete das Mono-Projekt, eine Plattformunabhängige Laufzeitumgebung für .NET. Damit hatten wir eine Basis, in der gewohnten Microsoft-Umgebung zu entwickeln und die Software gegen Linux laufen zu lassen. Aus diesem Projekt wurde auch das heute vollständige umgesetzte Konzept der Plattform-Unabhängigkeit geboren. Im Jahr 2003 haben wir angefangen SAP als ein Zielsystem zu integrieren. Bei SAP synchronisieren wir nicht die gesamte Datenbank noch einmal in unsere Datenbank, sondern beschränken uns auf die Informationen zu Konten, Mitgliedschaften und Gruppen (dort Profile und Rollen genannt), wobei letztere nur gelesen werden. 2005 haben wir es dann erstmals geschafft, funktionsidentische Frontends sowohl auf dem PC als EXE-Datei als auch im Browser laufen zu lassen, wobei in beiden Fällen das selbe Compilat verwendet wird. Das war notwendig, da immer mehr Kunden Intranet-Lösungen zu unserem Produkt haben wollten, insbesondere was den Bereich der Selbstbedienung der Anwender betrifft. Die Firma Völcker Informatik AG hat zum heutigen Tag 55 Mitarbeiter, davon arbeiten 12 in Dresden. Dresden ist der Standort der Firma in dem komplett die Bereiche Produktentwicklung, Qualitätssicherung, Dokumentation und Support abgewickelt werden. 2) heutiges Arbeitsgebiet von VI 2.1 Compliance Was ist eigentlich Compliance? Leo.org übersetzt das mit - in Übereinstimmung mit einer Bedingung - in Erfüllung einer Bedingung Wozu benötigen wir Compliance? Schauen wir ein paar Jahre zurück, auf das Platzen der großen Internetblase. Kann sich noch jemand an den Enron-Skandal erinnern? Dieses Energie-Unternehmen in den Vereinigten Staaten hat Spekulations- und Scheingeschäfte innerhalb der Firma gemacht. Zum Schluß implodierte das gesamte Spekulationsgebilde mit einem Riesenknall und einigen Milliarden Dollar Verlusten. Als Reaktion darauf wurde in den USA ein Gesetz verabschiedet, der „Sarbance-Oxley-Act“ (SOX). Dieses verpflichtet Unternehmen, Regeln der innerbetrieblichen Sauberkeit zu definieren, einzuhalten und zu überwachen. Solche Regeln sind z.B. daß jemand, der Einkäufe über 1000 $ auslösen darf, nicht gleichzeitig auch zeichnungsberechtigt für die dazugehörigen Überweisungen ist. Wenn eine solche Rechtekonstellation zusammentrifft, dann ist der Versuchung Tür und Tor geöffnet. Das sind Risiken, die in der Unternehmensbilanz benannt und bewertet werden müssen. Die Einhaltung dieser Regeln muß nicht nur auf allgemeiner organisatorischer Ebene, sondern ausdrücklich auch auf der Ebene der EDV-Zugriffsrechte sichergestellt werden. Und was geht uns das in Deutschland an? Die Beantwortung der Frage ist relativ einfach: Jedes Unternehmen, das auch an amerikanischen Börsen gehandelt wird, ist verpflichtet eine Bilanz zu liefern, in der auch die Einhaltung solcher Regeln gesichert ist. Das ist Bestandteil des Wirtschaftsprüfertestats. Es gibt aber auch bei uns gesetzliche Regelungen, die eine Regeldefinition und – Überwachung fordern. In Deutschland haben wir z.B. das Energiewirtschaftsgesetz. Das Energiewirtschaftsgesetz sagt unter anderem sinngemäß aus, daß, wenn eine Firma Energieerzeuger ist, ein eigenes Endkundengeschäft betreibt und auch Endkundengeschäft für Wiederverkäufer organisiert, niemand von diesen 3 Bereichen dem anderen in die Karten schauen darf. Ansonsten könnte ich ja als Endkundenbetreuer eines Energieerzeugers mal eben die Kundenliste der YelloKunden nehmen, alle abtelefonieren und versuchen sie zurückzugewinnen. Da muß also eine Wand im Unternehmen existieren, welche auch auf EDV-Ebene repräsentiert wird. Das heißt, daß Leute, die in dem einen Bereich arbeiten nicht auf die Ordner und Applikationen der Leute aus einem anderen Bereich zugreifen können und umgekehrt. Ein ähnliches Gesetz gibt es auch in Deutschland im Bereich Aktien- oder Bankenrecht. Jemand, der im Kundenauftrag mit Aktien handelt, darf sich in seinen Rechten, Befugnissen und Informationen nicht überschneiden mit jemandem, der Firmenfusionen, Firmenverkäufe oder Aufspaltungen im Auftrag der Bank bearbeitet. Im anderen Fall wäre die Gefahr eines Insider-Geschäfts gegeben. Dem Gesetz muß derart Genüge getan werden, daß eine Trennung auch im EDV-Bereich existiert. Das Thema Compliance befaßt also immer mit Regeldefinitionen der Art „Es darf nicht sein, daß jemand... “ Z.B. „Es darf nicht sein, daß jemand Zugang zu der Gruppe A und zu der Gruppe B und zu dem Ordner C hat und sowohl die Applikation D als auch die Applikation E verwenden darf.“ Weiterhin gefordert ist beim Thema Compliance eine dauerhafte und lückenlose Aufzeichnung aller Rechtezuweisungen, aller Rechteabweisungen und in dem Fall, daß eine Regelverletzung aufgedeckt wird, auch eine zeitnahe Benachrichtigung desjenigen, der für die Überwachung dieser Regel zuständig ist, erfolgt. „Es darf nicht sein, daß jemand...“ Wer ist dieser „jemand“? Im Sinne der Gesetze ist damit immer eine Person gemeint. Die Rechtsprechung kennt keine Konten, verantwortlich sind immer Personen. Eine Person hat jedoch unter Umständen mehrere Konten in den unterschiedlichsten Zielsystemen. Und für diese Person müssen die Regelverletzungen aufgedeckt bzw. gleich vermieden werden. Denken Sie jetzt mal an die EDV-Landschaften, die Sie bisher kennengelernt haben. Haben Sie da irgendwo schon einmal eine Person als abstraktes Objekt gesehen? Es werden immer nur Konten verwaltet. 2.2) Identity - Management Es existiert Uneinigkeit darüber, was eine Identität ist, manch einer meint die Person, andere meinen damit Konten. Im Sinne von Compliance sind aber immer beide im Zusammenhang zu betrachten. Das Ziel von Identity – Management ist es, zu jeder Zeit die Information über jede Identität und ihre Berechtigung zur Verfügung haben, manipulieren und auswerten zu können. Es nützt nicht, eine Überwachung von 2 Konten zu machen, es geht um die Person – der Bankangestellte, der nicht gleichzeitig zwei sich ausschließende Rechte haben darf, egal mit welchen Konten er sie erreicht. Rechte sind z.B. Access-Control-Lists im ActiceDirectory oder Transaktionen in SAP. Solche Rechte werden im Normalfall an Gruppen gebunden. Es gibt eine einzige Stelle, wo es sinnvoll ist, ein Recht an ein einzelnes Konto zu binden, und das ist das Recht auf dem Home-Verzeichnis eines Nutzers. Gruppen als Träger der Rechteinformationen gibt es heute in jedem Konten verwaltenden System (Betriebssysteme, SAP, Notes, auch Mail-Verteilerlisten sind „nur“ Gruppen ) Für die Überprüfung von Compliance reicht es also im Normalfall aus, die Gruppenmitgliedschaften zu überwachen, sofern die Rechte der Gruppen ordentlich dokumentiert sind. Zusammenfassung: Identity - Management ist das Verwalten von Informationen über Person, ihre Konten und deren Gruppenmitgliedschaften, das Aufzeichnen von Veränderungen und das Anbieten von Auswerte-Möglichkeiten. 2.3) Provisioning Das letzte Schlagwort in der Sammlung lautet Provisioning – frei übersetzt die „Versorgung“. Das meint die Versorgung einer Person mit Konten in einem bestimmten Zielsystem und die Versorgung eines Kontos mit Gruppenmitgliedschaften. Im erweiterten Sinne bedeutet das auch die Versorgung einer Person mit materiellen Gütern wie z.B. einem PC oder Telefon oder allem Sonstigen, was die Person für ihre Tätigkeit benötigt. Die Zielstellung, welche hinter dem Schlagwort Provisioning steht, lautet: Betritt jemand ein Unternehmen, so soll er innerhalb kürzester Zeit arbeitsfähig gemacht werden, auch EDV-technisch, d.h. er muß ein Konto bekommen z.B. im Active Directory, er muß ein Postfach erhalten, muß in bestimmte Rechtegruppen aufgenommen werden, muß ein Portfolio an Applikationen zugeteilt bekommen und einen PC auf den Schreibtisch bekommen, der ein passendes Betriebssystem und eine korrekte Netzanbindung hat. Wer etwas vertraut ist mit der Materie weiß, es gibt Unternehmen, in denen dauert es wirklich vom Eintritt des Mitarbeiters bis zu dem Zeitpunkt, an dem er EDV-mäßig arbeitsfähig ist, 2-4 Wochen. Es kann sich solange hinziehen, weil viel Papierkram von vielen Leuten ausgefüllt und unterschrieben werden muß bis sich dann jemand hinsetzt und wirklich das Konto anlegt. Das Gegenstück dazu ist, jemand verläßt das Unternehmen. Da mögen aber bitte innerhalb weniger Minuten sämtliche Konten nicht mehr verwertbar sein – egal ob sie nun gelöscht oder gesperrt werden, oder nur aus allen Gruppen entfernt werden. Hauptsache, man kann mit den Konten nicht mehr arbeiten. In der Praxis dauert es allerdings oftmals mehrere Jahre, bis auch wirklich das letzte Konto gesperrt oder gelöscht ist. Gesamt-Zielstellung Identity - Management, Provisioning und Compliance Eine Person soll genau über die Konten und Berechtigungen verfügen, die für ihre Tätigkeit notwendig sind, genau für den Zeitraum in dem das erforderlich ist. Sämtliche Arbeitsschritte, die Änderungen an diesen Daten vornehmen, sind zu dokumentieren. Das Berechtigungsportfolio darf keine der definierten Regeln verletzen bzw. sind diese Regelverletzungen aufzuzeichnen und kurzfristig den Verantwortlichen zu melden. Wie gelangt man nun eigentlich zur Mitgliedschaft in einer Gruppe, sei es nun Applikations- oder Rechtegruppe? Wir haben 3 mögliche Herangehensweisen: - Der erste Weg ist der Klassiker: Ich nehme das Management-Werkzeug des Betriebssystems nehme meinen Account, füge ihn in die Gruppe ein und speichere ihn. So hat keiner einen Überblick oder eine Benachrichtigung und somit weiß auch keiner, wer dies wann getan hat. - Die bessere Wahl ist ein Ablauf von Bestellung, Genehmigung und Zuweisung. Eigentlich wird hier lediglich das Verfahren abgebildet, welches in - den meisten Unternehmen papiermäßig abläuft und am Ende mit den technischen Mitteln der Direktzuweisung (s.o.) realisiert wird. Die 3. Variante ist die Erbschaft aus Strukturmitgliedschaften bzw. aus Rollen. Egal, welches der beiden letztgenannten Verfahren wir benutzen, wir haben es an diesen Stellen jetzt immer mit Betriebsdatenabbildungen zu tun, da die Erbschaft aus einer Strukturzugehörigkeit erfolgt bzw. der Besteller und der Genehmiger in einer betrieblichen Korrelation zueinander stehen. Oftmals ist z.B. der Genehmiger der Kostenstellenverantwortliche, da dieser später auch die zugehörige Rechnung bekommt. Bei der Deutschen Telekom Immobilien GmbH haben wir es so implementiert, daß jeder Kostenstellenverantwortliche am Monatsende per E-Mail ein PDF zugestellt bekommt mit dem Titel „Ihre EDV-Kosten für diesen Monat für ihre Mitarbeiter“. Aufgeführt sind dort alle Kosten für PC-Abschreibung oder Leasingraten, Applikationsnutzung oder Speicherverbrauch auf den Servern. All diese Informationen sind letztlich in der Datenbank vorhanden und müssen nur noch per Report strukturiert werden. Die EDV-Kostenstellen werden in der Kostenrechnung als Verrechnungskostenstelle umgelegt, d.h. die EDV-Abteilung ist an jedem Monatsende als interner Firmendienstleister kostenmäßig auf +/- Null gestellt. Wir haben also immer eine gewisse Betriebsdatenabbildung durchzuführen. Wie diese aussieht, soll unser letzter Punkt sein bevor wir uns der konkreten Implementierung zuwenden. 2.4 Betriebsdatenabbildung Bei der Betriebsdatenabbildung gibt es mehrere Ansätze. Ich habe mit Herrn Professor Koch von der HTW herzliche Streitgespräche durchgeführt. Prof. Koch ist einer der X-500 Gurus und ebenso ein Motor der Unix-Gemeinde. X-500, ist vereinfacht gesagt, ein Modell zur hierarchischen Strukturierung von Organisationsdaten als Container und der Zuordnung von Konten in diese Container. Das ist das Modell mit dem viele Vertriebsleute Erfolg haben, weil es genauso aussieht, wie sich mancher Vorstand seine Firma vorstellt. Ganz oben ist der Chef, darunter bauen wir ein paar Container an, welche die Hauptabteilungen darstellen. Darunter werden erneut Container aufgebaut, die dann Unterabteilungen verkörpern. Schließlich folgen die Kleinstabteilungen. Es ist also ein richtig schönes hierarchisches System, in dem ich auch etwas durchvererben kann. Es gibt allerdings ein paar Probleme z.B. das Thema Standorte. Die IP-Konfiguration der Rechner ist standortabhängig. Gut, lösen wir das Problem, indem wir auf der ersten Ebene unserer Hierarchie Container für die Standorte einfügen und darunter spannen sich dann die Abteilungen auf. Das ist immer noch optimal aus der Sicht eines Vorstandsvorsitzenden. Dann gibt es aber noch die Kostenstellen. Nun wird es langsam unübersichtlich, da man sie nicht mehr in eine einzelne Hierarchie hineinbekommt und außerdem im X-500 jedes Konto nur in genau einem Container Mitglied sein kann. Vor ca. 6 Jahren hatten wir die dankbare Aufgabe bei der Wirtschaftsprüfungsfirma KPMG eine Analyse zur Modellierung der Verteilerlisten zu erstellen. KPMG ist ein Unternehmen, welches andere Unternehmen berät wie diese ihre Betriebsabläufe aufzubauen und wie sie sich zu strukturieren haben. Im E-Mail - System gab es eine Menge definierter Verteilerlisten und KPMG wollte einen Automatismus haben, mit dem jemand aufgrund seiner Zugehörigkeit zu einem Standort, zu einer Abteilung usw. automatisch Mitglied in einer Verteilerliste wird und die entsprechenden Informationen, die an diese Verteilerliste gesendet werden, auch erhält. Die 3 Klassiker in der Betriebsstrukturierung hatten wir sofort identifiziert: Abteilung, Kostenstelle und Standort – alles kein Problem. Die Kostenstellen ergaben sich aus Sicht der Controller. Die Mitgliedschaft im Beratungsprojekt X oder Y ist die nächste Ebene. Dann kamen noch die Fachgebiete hinzu z.B. Beratung in Land- und Forstwirtschaft, dazu die Interessengebiete „Ja, ich interessiere mich auch für die Nahrungsgüterwirtschaft“. Weiterhin gibt es die Partnerschaften. KPMG ist keinesfalls ein homogenes Unternehmen, sondern viel mehr eine Vereinigung mehrerer Sozietäten mit gemischten Eigentümerschaften. Und dann gibt es noch Spezialisierungsrichtungen: Der eine Mitarbeiter ist verantwortlich für Prüfung und Testierung, der andere ist für die Betriebsorganisation zuständig und der Dritte für die Finanzplanung. Das sind also insgesamt 8 Dimensionen, in denen KPMG strukturiert ist. Wir können davon ausgehen, daß jede Firma eine n-dimensionale Abbildung benötigt, wobei n beliebig groß sein kann. Wir haben also eine n-dimensionale Matrix-Sicht. Jede dieser Sichten ist bei uns letztendlich auch implementiert als ein Baum, jedoch gegenüber X-500 mit einigen entscheidenden Unterschieden: - Jeder Nutzer kann Mitglied in beliebig vielen Containern auch innerhalb eines einzigen Baumes sein - Mitglied sind die Personen, nicht die Konten - An jeden Container kann man Rechte aus allen Zielsystemen zuweisen, weiterhin auch Konstrukte für die Zuweisung für z.B. PCs 3. Lösungsansätze für IdM, Provisioning und ComplianceCheck 3.1 Lösungsansätze der Marktführer MetaDirectory - Projekte In den letzten Jahren gab es den Hype der Meta-Directory-Projekte. Die Anbieter am Markt hatten inzwischen alle erkannt, daß eine n-dimensionale Matrix und eine X-500 Abbildung nicht so recht zueinander passen. Also definierten sie ein neues Directory, legten dieses über das vorhandene und nannten das Ganze ein Meta-Directory. Wenn man die Dimensionen vergleicht, kommt man schnell zu dem Schluß: „Das kann nicht funktionieren.“ Die Meta-Directory-Projekte sind auch alle hinsichtlich einer sauberen Betriebsdaten-Abbildung gescheitert. Identity Management – Systeme (IdM) Die meisten Anbieter von IdM führen mit Kunstgriffen die Person als Objekt ein, legen jedoch nur die Referenzen zu den verwalteten Konten ab. Es erfolgt also keine komplette Abbildung des Zielsystems (Bsp. Nur Ablage des DistinguishedName). Dabei treten jedoch einige Probleme auf: - Wird ein Objekt umbenannt oder geändert, stimmt die Referenz nicht mehr, das System ist inkonsistent. - Die Zuordnung der Eigenschaften als auch Zuordnung von Personen zu Konten erfolgt über Mapping – Regeln z.B. zwischen Accountname oder Email-Addresse zu Eigenschaften der Person wie Vorname und/oder Nachname Das klappt im besten Fall für 98 % aller Objekte, meist jedoch nur im Bereich zwischen 60 und 80 % aller Objekte. Aber selbst 2 % Restmenge bedeuten das Scheitern des Projektes, weil damit a) automatisches Management über die Meta-Ebene nicht mehr zu definiert richtigen Ergebnissen führt. b) schon ein einziger Verstoß gegen Compliance - Regeln zur Verweigerung eines Testats führen kann. - Sollen Objekte betrachtet oder geändert werden, ist ein Zugriff auf das Zielsystem notwendig, es muß also am Standort der Management – Software verfügbar sein. - Sollen Listen von Objekten gezogen werden, so benötigt man viel Zeit. Wir haben Anwendungsfälle, bei denen wir die Mitglieder in einem Container (2500 Konten), als eine Liste im Frontend produzieren müssen. Als Reaktionszeit eines Frontends werden nur Zeiträume bis 3 Sekunden akzeptiert. Mit Direktzugriffen auf die Zielsysteme schafft man das nicht annähernd. Es gibt also auf diesem Gebiet einen Glaubenskrieg – machen wir ein Store-ByReference (was u.a. in den Meta-Directory-Projekten verwendet wird) oder mache ich ein Store-By-Value (unser Weg) d.h. alle Daten liegen komplett in der Datenbank. Warum haben wir uns für die Datenbank entschieden? Zum einen ist das das einzige wirklich transaktionssichere System. Für diesen Zweck sind relationale Datenbanken entwickelt worden. Und es ist auch die einzige Technologie, die gut geeignet ist für Massendatenverarbeitung. 3.2 Lösungsansatz von VI 3-Ebenen Architektur Letztendlich gesehen, haben wir in unserem Produkt eine klassische 3-EbenenStruktur, bestehend aus einer Datenbank, darüber die Objektschicht und einer Präsentationsschicht. Auch die automatische Verarbeitung auf den Servern funktioniert wie eine Präsentationsschicht, da auch sie immer durch die Objektschicht hindurch geht. ObjectLayer ObjectLayer Datenbank Nutzdaten Metadaten Die Datenbank haben wir logisch in zwei Bereiche eingeteilt. Zum einen haben wir die Nutzdaten, welche die konkreten Informationen über Personen, Betriebsdaten, Konten, Mitgliedschaften, Gruppen beinhalten (pay-load). Zum anderen gibt es die Metadaten, welche die gesamte Dialogsteuerung, Queues für asynchrone Verarbeitung sowie die komplette Systemkonfiguration umfassen. Das Nutzdaten- Modell enthält Tabellen für: - Die Person und ihre 1:n Abbildung zu Konten - Beliebige Betriebsdaten-Strukturen mit beliebigen Mitgliedschaften als Fremdschlüssel oder auch als m:n-Abbildung, um die n-dimesionale Matrix des Unternehmens darstellen zu können. - Die vollständige Abbildung der zu verwaltenden Zielsysteme. Über der Datenbank liegt eine Objektschicht. In der Objektschicht ist eigentlich vom Objekt selbst oder von Klassendefinition her nichts programmiert. Die „leere Hülle“ der Objekte wird zur Laufzeit aus dem datenbankschema erzeugt. Die Funktionsweise der Klassen ergibt sich erst im Zusammenspiel mit den Meta-daten aus der Datenbank. Wir haben je Tabelle eine Objektklasse. Davon abgeleitet gibt es je nach Bedarf weitere Teilklassen. Je Spalte ist ein Property definiert. Zur Verfügung steht ein Satz von Datenbank-orientierten Methoden (Load, Save, GetValue, PutValue) und Events (Insert, Update, Delete). Wir stellen Ausdrucksmittel für die Quernavigation (Objectwalker) zur Verfügung, mit denen sich auf der Ebene C# Fremdschlüsselbeziehungen verfolgen lassen. Es gibt die sogenannten Customizer in der Objektebene. Diese enthalten nicht änderbare Nebenwirkungen der Objekte. Ein Beispiel dafür ist das Wechselspiel der Flag UserCanNotChangePassword UseMustChangePasswordAtNextLogon im Objekte ADSAccount. Über die Metadaten der Datenbank können weitere konfigurierbare Nebenwirkungen geladen werden, die dem Kunden offen gelassen wurden. Beispiel dafür sind Bildungsregeln für Postfächer. Über Serverkomponenten, die auch gegen die Objektschicht arbeiten, erfolgt die vollständige bidirektionale Synchronisation mit den Zielsystemen. Das Management über Frontends erfolgt immer durch die Objektschicht hindurch. Als Ergebnis gibt es eine Veränderung von Nutzdaten. Parallel dazu werden auch Metadaten verändert, vorzugsweise in Queues für asynchrone Verarbeitungen. Von den Queues holen sich Server die Informationen ab und verarbeiten diese. Gleichzeitig befinden sich Server aber auch in der Rolle, daß sie Informationen und Aktionen (wie ein normales Frontend) wieder einstellen können. In den einschlägigen Studien zum Thema Identity Management und Provisioning (z.B. Burton und Gartner) tauchen immer wieder zwei Begriffe auf, über die sich die Gelehrten allzu gern streiten: Local Agent und Remote Agent. Ein Agent ist in dem Sinne ein Stück Software, welches Manipulationen an Konten im Zielsystem vornehmen kann. Der lokale Agent: Ich mache etwas über eine Remote-Konsole auf einem Server und lasse dort alles ausführen. Der Remote Agent: Ich sitze an meinem Arbeitsplatz und habe einen Durchgriff durchs Netz und mache meine Änderungen aus der Entfernung. Nach diesen Definitionen ist unser Produkt etwas, was man konsequenterweise als Distributed Agent bezeichnen muß. Betrachten wir zum besseren Verständnis den Vorgang „Anlegen eines Kontos in der ADS“. Im Frontend hat das Konto seine Eigenschaften bekommen und soll nun in das Zielsystem publiziert werden. Die erste Aktion hierfür ist das Anlegen des Kontos selbst. Manch einer glaubt, das wäre schon alles gewesen, doch die eigentliche Arbeit beginnt jetzt erst. Nach dem Anlegen auf dem Domain-Controller folgt ein weiterer Bearbeitungsschritt, denn der Nutzer benötigt ein Home-Verzeichnis. Dazu muß ich einen geeigneten Home-Server aus den Betriebsdaten auswählen, im Normalfall wird das standortabhängig sein. Auf dem Homeserver muß ich ein Verzeichnis anlegen, dieses sharen und Rechte für den Nutzer vergeben. Des Weiteren benötigt der Nutzer ein Postfach, welches ich sinnvollerweise auf dem Exchange-Server anlege. Aber sowohl bei der Rechtevergabe auf dem Home-Server als auch beim Anlegen des Postfaches auf dem Exchange-Server muß ich warten bis die ADS eigene Replikationen mir das Konto auf dem aktuellen Server zur Verfügung stellt. Dann muß das Konto in Rechtegruppen und Verteilerlisten aufgenommen werden, was sinnvollerweise wieder auf dem Domain-Controller passiert. Wir bevorzugen diese Vorgehensweise aufgrund der Installierbarkeit, der Lastverteilung und der Sicherheit der Daten. Wenn ich einen Dienst auf einer Maschine installiere, dessen Aktionsgebiet auf die Maschine selber beschränkt ist, bekomme ich Rechtesituation und Betriebsstabilität viel einfacher konfiguriert, als wenn ich Aktionen ausübe, bei denen man durchs Netz durchgreifen muß. Dazu müßte ich einem Konto Rechte auf entfernte Ressourcen erteilen. Sobald sich aber an Kontensituationen oder Netztopologie irgend etwas verändert, ist solch eine Zuordnung von Rechten immer problembehaftet. Deswegen liegt unsere Konzentration auf lokaler Ausführung. Jeder Server holt sich aus der Queue in der Datenbank die Aufgaben ab, die durch ihn zu bearbeiten sind und meldet sein Verarbeitungsergebnis zurück. Darauf basierend besitzen wir einen SchaltMechanismus für Prozeßabläufe, durch die im Anschluß der möglichen Folgeschritt freigeschalten wird. 3.2.1 Vorgehensweise von VI im Projekt Die schwierigste Phase in IdM-Projekten ist die die Inbetriebnahme und hierbei wiederum das Thema Datenkonsolidierung. Im Laufe der Jahre hat sich bei uns ein Standard-Vorgehen etabliert. Die Daten zu den Betriebsstrukturen werden durch Importe oder durch manuelles Anlegen erzeugt. Die Personen werden aus einem HR-System importiert, das klappt zumindest für alle die, die auf der Lohnliste stehen. Jetzt fehlen noch externe Mitarbeiter von Dienstleistern bzw. Leiharbeiter. Weitere Personendaten oder auch weitere Eigenschaften von Personen werden durch Import aus Telefonbuch-Applikationen, Telefonanlagen-Speichern oder später direkt aus Konten gewonnen. Danach werden alle relevanten Zielsysteme mit Konten, Gruppen und Mitgliedschaften eingelesen. Auf Basis dieser Daten machen wir eine erste Zuordnung der Personen zu den Konten. Diese Zuordnung erfolgt durch einmaliges Anwenden von Mapping – Regeln in den Fällen, bei denen die Regel ein eineindeutiges Ziel ermittelt. Mit dieser Methode erreicht man ca. 60-80 % Datenqualität. Die so erzeugten Daten gehen als Korrekturlisten an die Abteilungen, da auf dieser Ebene die Personen durch direkten Kontakt bekannt sind und die Informationen oft wesentlich aktueller vorhanden sind. Den Abteilungsleitern wird ein Frontend im Intranet zur Verfügung gestellt, mit dem sie ihren Änderungen vornehmen können. Bis hierher kommen wir auf über 95 % Datenqualität. Alle Konten, die sich bis zu diesem Stand nicht zuordnen lassen, werden gesperrt. Wir gehen aus Erfahrung davon aus, daß sich der Inhaber des Kontos in der EDVAbteilung melden wird, sofern er noch Bedarf hat. Die ausgelesenen Gruppen-Zuordnungen der Konten werden soweit möglich umgesetzt auf Erbschaften über Betriebsdaten, sofern die Beziehung zwischen z.B. einer Abteilung und einer Gruppenmitgliedschaft eindeutig ist und der Kunde dies wünscht. Ein anderer oder manchmal auch zusätzlicher Weg ist die Umsetzung der Gruppenzuordnungen auf Bestellungen im IT-Shop. Die Zuordnungen werden so aufbereitet, als ob sie im Intranet bestellt, genehmigt und zugeordnet wären. Das gibt dem Kunden die Möglichkeit, solche Zuordnungen einfach abbestellen zu können. Die Zuordnung der Konten zu Personen kann ebenfalls wie eine ITShop-Bestellung aufbereitet werden, so daß z.B. ein Abteilungsleiter für seinen Mitarbeiter ein Konto wieder abbestellen kann, wenn er dies nicht mehr benötigt. 4) Plattform - unabhängige Implementierung 4.1 Die Voraussetzungen bei VI Die Wurzeln von Völcker Informatik liegen ganz eindeutig im Microsoft-Umfeld Alles was bisher beschrieben wurde, hatten wir über die Jahre schon Stück für Stück in C++ und COM - Technologie (für die Zugriffs- und Objektebene) bzw. in Visual Basic für die Frontends implementiert. Als Datenbank diente MSSQL in den Versionen 6.5, 7 und auch 2000. Alle Mitarbeiter haben mit Microsoft DevStudio 5 und 6 gearbeitet, VI-Editor und Arbeit ohne einen Schritttest-Debugger hat niemand mehr akzeptiert. Die Niederlassung Dresden setzt sich nach Aufgaben heute wie folgt zusammen (Teilzeitverträge und Aufgabenteilungen sind anteilig umgerechnet auf ganze Stellen) Objektschicht Zielsystem –Abgleich Standard-Frontends (Fat + Web) QS Standard-Prozesse Kundenspezifische Frontends Dokumentation Entwicklung primäre Datenbank Umsetzung Oracle Support 1 1 2 1,5 0,75 1 1 1 0,3 1,5 Das bedeutete, je nach Zählweise ca. 7 Leute für alle Entwicklungen Für alle Software-Ebenen mußte eine Entscheidung fallen für ein System unter dem primär entwickelt wurde. Alle anderen Plattformen müssen dann per Anpassen / „Abschreiben“ nachgezogen werden. Bei der Entwicklung auf der jeweiligen Primärplattform müssen die Einschränkungen durch die anderen Plattformen immer schon berücksichtigt werden. Alles was gebaut wird, muß Unit-Tests erhalten, die identisch auch in der Sekundär - Implementierung ablaufen. 4.2 Die Kundenforderungen Die Kundenwünsche beinhalten Plattformunabhängigkeit hinsichtlich - Datenbank - Zugrunde liegendes Betriebssystem, Programmiersprache und Laufzeitumgebung - Frontend-Technologie als Exe bzw. als Browser-Frontend wobei der Webserver und der Browser selbst auch wieder Plattformunabhängig sein sollen. Insgesamt ergibt das die nachfolgend skizzierte Vielfalt an Möglichkeiten 4.3 Die Lösungswege Das Ergebnis soll hier schon einmal vorweggenommen werden. Aus unserer Sicht hat man genau 3 Lösungsmöglichkeiten, um eine Software plattformunabhängig zu entwickeln. Nr. 1 die schöne heile Welt: Wir haben identischen Schnittstellen auf allen Plattformen. Dazu entwickelt man einen Quelltext, compiliert diesen und läßt das Ergebnis auf alle Plattformen laufen. Nr. 2 die ähnliche Welt: Die Zielumgebungen sind sich zumindest weitgehend ähnlich, haben eine ausreichend großen Durchschnittsmenge, so daß sich eine Entwicklung auf einer Meta-Ebene lohnt. Das bedeutet, daß man auf einer abstrahierten Ebene entwickelt und dann entweder zur Laufzeit oder zur Generierungszeit aus dieser Meta-Ebene ein Programm erzeugt, das auf den jeweiligen Plattformen läuft. Nr. 3 die Unterwelt: Die Zielumgebungen sind so unterschiedlich, daß getrennte Implementierungen notwendig sind. Üblicherweise wird für ein Primärsystem entwickelt und nach erfolgten Tests der Code anschließend durch Abschreiben in eine oder mehrere Sekundärimplementierungen übertragen. In Reinform trifft man diese Möglichkeiten in der Realität fast nie an. Meistens treten Mischformen auf. 5) Konkrete Implementierung der Ebenen 5.1 Die Businesslogik / Objekt-Ebene Für die Implementierung einer plattformunabhängigen Objekt - Ebene standen im Jahr 2002 zwei relevante Systeme zur Auswahl: Die zuerst untersuchte und damals auch bekanntere Grundlage war Java. Es war damals schon weit verbreitet und hatte vor allem serverseitig eine große Akzeptanz erreicht. Die Fat - Clients waren jedoch recht langsam und instabil. Für die Zukunftssicherheit der Entscheidung kam erschwerend hinzu, daß Java kein offener Standard ist, sondern unter Hoheit der Firma SUN steht. Als technisches Problem stellte sich die Einbindung von nativem Code heraus, welcher jedoch bei der Ansteuerung z.B. einer ADS oder eines Notes-API benötigt wird. Die Alternative hieß .NET Framework mit C# als Entwicklungssprache. Das war für uns aufgrund unserer Vergangenheit eine vertraute Entwicklungsumgebung mit der auch native Windows-Frontends möglich waren. .NET war eingereicht als ECMA-Standard und eine Portierung auf andere Betriebssysteme war mit dem quelloffenen Mono im Entstehen. Mono war zwar anfangs noch nicht ausgereift, Probleme konnten von uns aufgrund der Quelloffenheit gefixt und an die Mono-Community eingereicht werden. Die Einbindung von bestehendem Code war für eine Übergangszeit bzw. für die direkte Betriebssystemansteuerung möglich. Letztendlich trafen wir also unsere Entscheidung zugunsten .NET. Eine totale Plattformunabhängigkeit läßt sich nicht erreichen, es gibt immer Fallstricke zu beachten. Einige Beispiele dafür sollen nachfolgend kurz benannt werden. - - - Pfade im Dateisystem Linux ist in diesem Bereich Case Sensitiv, Windows ist Case Insensitiv. Beide Betriebssysteme haben andere Trennzeichen und andere Verzeichnisstrukturen (Laufwerksbuchstaben) Fehlende Features Linux kennt keine Registry und keine COM-Interfaces Unterstützung für Oberflächenbibliotheken Es gibt erhebliche Unterschiede zwischen WinForms und GTK# externen Bibliotheken In den Anfangszeiten gab es für MONO keine vollständige VB.NETUmsetzung Verwendung von nicht portablen externen Bibliotheken Zugekaufte Controls oder Bibliotheken enthalten oftmals native Betriebssystem-Aufrufe, das ist z.B. bei fast alle Reporting-Werkzeugen der Fall Nutzung von Tools, die nur auf einem der Systeme zur Verfügung stehen (z.B. Robocopy vs. Rsync) Die Grundregel lautet hier: Soweit wie möglich abstakt implementieren und z.B. Path.Combine statt String.concat verwenden. Wenn es wirklich massive Unterschiede gibt, greift Methode 3: Man verwende einen Case-Block, der nach Betriebssystemen differenziert. Zu diesem Zweck kann man ein zentrales Property unserer Klassenbibliothek zur Unterscheidung abfragen. 5.2 ) Datenbank-Ebene Was ist das Schöne an Standards? Daß es so viele davon gibt! Es gibt einen ANSI-SQL-Standard. Man kann sich daran orientieren und es ist als Lehrbeispiel auch gut zu verstehen. Daneben gibt es die Implementierung von Microsoft mit dem Namen Transact-SQL, meist abgekürzt mit T-SQL. Weiterhin gibt es eine Implementierung von Oracle, die sich PL/SQL nennt. Die nachfolgenden Aussagen sind nicht wissenschaftlich, sondern eher im Gefühlsbereich angesiedelt. Es gibt Überschneidungen und Differenzmengen zwischen MSSQL, Oracle und dem ANSI-Standard. ANSI-SQL ist von Haus aus, was Abläufe und prozentuale Elemente betrifft, etwas schwach auf der Brust – Da ist eigentlich gar nichts definiert. T-SQL PL/SQL ANSI-SQL Unser Ziel war immer offen zu bleiben für die spätere Integration weiterer Datenbanksysteme. Deshalb wurde vor Grundsatzentscheidungen auch immer die Machbarkeit gegen PostgreSQL abgetestet. DB2 haben wir außen vor gelassen, da es bei unseren Kunden so gut wie nicht vorkommt und MySQL mußten wir ignorieren, da es mit Triggern und SPs noch nicht so weit war. 5.2.1. Generierung und Single Source Die Datenbank ist der Kern unseres Produktes, die Stelle, wo alle Informationen zusammenlaufen. In der Codestatistik im Anhang kann man erkennen, wie sich dieser Sachverhalt auch auf die Code-Menge auswirkt. Das konnten wir natürlich nicht alles zweimal machen. Deswegen ist es nötig zu differenzieren. Soweit wie möglich nutzen wir MetaEntwicklung aus einer einzigen Quelle. Das Datenbankschema wird mit einem schönen, alten Werkzeug gepflegt, das inzwischen schon 10 Jahre alt ist und ERWin heißt. Wir nehmen unsere Entity-Relationship-Modelle um das Schema zu definieren und daraus einen Report zu erstellen. Weiterhin haben wir ein kleines Generierungstool und generieren uns aus dem Report des Modells das eigentliche Schema. Die Generierung erzeugt das Schema mit allen Tabellen, Indizes, allen Anweisungen für referentielle Integrität (teilweise als Trigger, teilweise als Constraint). Im nachfolgenden Beispiel sehen wir die generierten Quelltexte für die Tabellendefinition für Betriebssystem-Informationen. Die beiden Texte sehen sich noch recht ähnlich, haben aber schon ein paar Unterschiede, die rot gekennzeichnet wurden. Bsp.: Create Table Create Table OS ( Ident_OS varchar(32) NOT NULL, UID_Licence char(38) NULL, Name varchar(64) NULL, Version varchar(64) NULL, IsServerOS bit default 0 NULL , IsClientOS bit default 0 NULL , XDateInserted datetime NULL, XDateUpdated datetime NULL, XUserInserted varchar(64) NULL, XUserUpdated varchar(64) NULL, XTouched char(1) NULL Primary Key (Ident_OS) ) go Create Index XIF1126OS on OS ( UID_Licence ) go Create Table OS ( Ident_OS Varchar2(32 ) NOT NULL, UID_Licence Varchar2(38 ) NULL, Name Varchar2(64 ) NULL, Version Varchar2(64 ) NULL, IsServerOS Number(1,0 ) default 0 , IsClientOS Number(1,0 ) default 0 , XDateInserted Date NULL , XDateUpdated Date NULL , XUserInserted Varchar2(64 ) NULL, XUserUpdated Varchar2(64 ) NULL, XTouched Varchar2(1 ) NULL , Primary Key (Ident_OS) ) go Create Index XIF1126OS on OS ( UID_Licence ) go Der Name von Tabellen darf bei Oracle aus historischen Gründen nur 30 Zeichen betragen, Microsoft hingegen erlaubt bis zu 260 Zeichen. Will man beide Systeme verwenden, muß man praktisch alles auf die kleine Variante reduzieren – also 30 Zeichen. Die Gültigkeit von Namen ist bei Oracle prinzipiell schemaweit. Bei Microsoft muß Indexname nur unikal sein im Zusammenhang mit dem Tabellennamen. Die Wertarten sind ein Thema für sich. Varchar ist Standard für alle variablen Zeichenketten. Oracle besitzt außerdem ein Varchar2. Oracle kennt zwar auch ein varchar, das ist aber kaum in Verwendung. Varchar2 wurde wahrscheinlich deshalb so genannt, weil es ein bißchen anders ist. Microsoft trennt strikt: eine leere Zeichenkette (’’) ist etwas anderes als ein Null-Wert. Oracle sagt, es ist dasselbe. Das kann einem ganz böse auf die Füße fallen, wenn man für beide Plattformen etwas entwickelt. Microsoft kennt für logische Informationen die Wertart Bit. Sie kann die Werte 0,1 und null annehmen und benimmt sich ansonsten wie andere numerische Werte. Oracle hingegen kennt einen richtigen boolean mit true und false. Damit wir aber wieder kompatibel in der ganzen darüber liegenden Umgebung sind, haben wir bei Oracle logische Werte generiert als Numeric (1,0) und interpretieren das auf der Objektebene als logischen Wert mit 0 und 1. Nach außen aus der Objektschicht kommt es als boolean mit true und false wieder an. Ein ganz böses Thema ist der ANSI-Join. Diese Notation kann Oracle überhaupt erst seit Version 9. Leider ist die Implementierung so instabil, da man bei Verwendung der ANSI-Notation Fehler in der Zugriffsschicht provozieren kann, wenn mehr als 5 (Version 9) oder 7 Tabellen (Version 10) beteiligt sind. Es gab im Jahr 2003 eine Vorstellungskonferenz für Yukon, was dann der Microsoft SQL-Server 2005 wurde. Steve Ballmer ist ja bekannt für seine oftmals humorigen Auftritte. Er hatte sich auf die Bühne gestellt und gesagt: „Microsoft is a Database – Company.“ Kichern, Lachen und Stöhnen im Saal. Aber er ließ sich nicht davon beirren und sagte den Spruch noch einmal. Seit ich den ANSI-Join von Oracle kenne, glaube ich Mr. Ballmer. Weitere Unterschiede, die in schon in der Generierung berücksichtigt werden müssen, sollen nachfolgend nur kurz benannt werden: Standard - Funktionen haben zum Teil unterschiedliche Name und Parametrierungen. Substring <-> substr left <-> substring(x,1) dateadd, datediiff <-> keine direkte Entsprechung Diese Funktionen haben wir in Oracle alle nachimplementiert, um sie in der gleichen Notation wie in MSSQL nutzen zu können. DDL-Anweisungen sind bei MSSQL innerhalb einer Transaktionen möglich, bei Oracle beenden sie die Transaktion. Bei MSSQL arbeiten wir aus historischen Gründen Case - Insensitiv, da das in Windows (Konten, Filename) auch so ist. Oracle kennt keine case-insensitiven Daten. Bei Vergleichen muß man also darauf Rücksicht nehmen. Bsp.: MSSQL: Oracle: Lastname = @Lastname upper(Lastname) = upper(v_Lastname) Besonders dramatisch ist das bei Fremdschlüssel - Beziehungen. Bisher war es uninteressant ob ein Wert in der Childrelation groß oder klein geschrieben war, jetzt haben wir auch in MSSQL dafür gesorgt, daß beide den gleichen Case haben. Der 2. Teil der Generierung, umfaßt die referentielle Integrität, was man als Trigger oder als Constraint bauen kann. Wir haben in manchen Fällen das eine, in manchen Fällen das andere gemacht. Nachfolgend sehen wir einen generierten Trigger, einmal die Microsoft-Implementierung und einmal die Oracle-Implementierung. Blau markiert sind die Bereiche, welche noch gleich sind, denn es sind einfach zu viele Sachen, die unterschiedlich sind. Es kommt aber aus derselben Source, aus demselben Schema - Entwurf. exec vidroptrigger 'vi_2LicencePurchase' go create trigger vi_2LicencePurchase on LicencePurchase for Update as begin declare @numrows int, @errno int, @errmsg varchar(255) if 0 = (select count(*) from inserted) + (select count(*) from deleted) return if (select count(*) from deleted, inserted where deleted.UID_LicencePurchase = inserted.UID_LicencePurchase ) <> (select count(*) from inserted) begin select @errno = 30002, @errmsg = '#LDS#Änderung des Primärschlüssels in Tabelle {0} ist nicht zulässig|LicencePurchase' goto error end end return error: create or replace trigger vi_8LicencePurchase before update on LicencePurchase for each row declare numrows int; errmsg varchar2(255); begin select count(*) into numrows from dual where ( :old.UID_LicencePurchase = :new.UID_LicencePurchase or (:old.UID_LicencePurchase is null and :new.UID_LicencePurchase is null)); if numrows = 0 then errmsg := '#LDS#Änderung des Primärschlüssels in Tabelle {0} ist nicht zulässig|LicencePurchase'; goto error; end if; return; Und dann gibt es noch das Thema: 5.2.2. liebevolle Handarbeit Stellen Sie sich folgenden Fall vor: Eine Person wird Mitglied in einer Abteilung. Es könnte sein, daß sich die Rechtesituation dieser Person ändert, indem die Konten der Person eine Gruppenmitgliedschaft oder irgendwelche Software erben. Demzufolge ist für die Zuweisung der Person zur Abteilung ein Trigger nötig, der einen asynchronen Berechnungsauftrag einstellt. Die Verarbeitung muß asynchron sein, da jede Antwortzeit des Systems über 3 Sekunden vom Anwender nicht akzeptiert wird. Wenn Sie sich mit einem Menschen unterhalten und dieser sie über 3 Sekunden lang starr ohne jede Regung ansieht, dann werden sie unsicher. Man wird skeptisch. Versteht er mich jetzt noch oder muß ich es noch mal sagen oder wie? Genauso gehen wir auch mit dem Computer um. Bei jeder Reaktionszeit unseres Frontends über 3 wird der Anwender unsicher. Die Trigger werden von Hand geschrieben, da wir bisher keinen gescheiten Weg zur Meta-Programmierung gefunden haben. Die Primärimplementierung ist MSSQL. Nachfolgend ein Beispiel für manuell doppelt implementierte SQL-Texte: create procedure viDropProcedure (@name varchar(64)) create or replace procedure viDropProcedure (in_name IN VARCHAR2 DEFAULT NULL) as begin declare @cmd varchar(255) declare @owner varchar(255) as DECLARE viDropProcedureSchritt SCROLL CURSOR for select rtrim(ROUTINE_SCHEMA) from information_schema.routines where ROUTINE_NAME = @name and ROUTINE_type = 'procedure' for read only OPEN viDropProcedureSchritt FETCH FIRST FROM viDropProcedureSchritt into @owner WHILE (@@fetch_status <> -1) BEGIN select @cmd = 'drop procedure ' + @owner + '.' + @name exec (@cmd) FETCH NEXT FROM viDropProcedureSchritt INTO @owner END close viDropProcedureSchritt deallocate viDropProcedureSchritt end go cursor schritt_VIDROPPROCEDURE is SELECT object_name FROM user_objects WHERE upper(object_name) = upper(in_name ) and upper(object_name) not like 'VIDROP%' and upper(object_type) = upper('procedure'); v_object_name varchar2(255); cmd varchar2(255); BEGIN open schritt_VIDROPPROCEDURE; loop fetch schritt_VIDROPPROCEDURE into v_object_name; exit when schritt_VIDROPPROCEDURE%notfound; cmd := 'drop procedure ' || v_object_name; EXEC_sql (VIDROPPROCEDURE.cmd); END LOOP; END VIDROPPROCEDURE; go Es gibt von der Grundstruktur noch ein paar Ähnlichkeiten, aber es läuft soweit auseinander, daß es nicht mehr automatisch umsetzbar ist. Wir haben uns allerdings die Arbeit des Abschreibens an einer Stelle ein bißchen erleichtert. Wir haben ein Word-Makro gebaut welches ein paar bedingte Ersetzungen enthält. Der MSSQL-Text wird in das Word-Dokument gepackt, das Makro läuft und wir haben die Rohübersetzung für Oracle. Das mag jetzt etwas laienhaft anmuten, hat aber einen sehr praktischen Hintergrund. Wir haben einige Tools ausprobiert, die versprachen, eine SQL-Notation in eine andere umzusetzen. Keines von denen hat Code produziert, der verwendbar gewesen wäre. Entweder gab es Fehler beim Parsen oder der erzeugte Zielcode hat das 10-fache Volumen des primären Codes oder der Zielcode war einfach nur syntaktisch oder inhaltlich falsch. Die größte Erfolgsquote hatten wir letztendlich bei Verwendung des Word-Makros. Die Nacharbeit hält sich in Grenzen und die Struktur der beiden Texte ist immer noch so ähnlich, daß man Änderungen, die sich ja immer im Laufe einer Weiterentwicklung ergeben, in der Sekundär - Implementierung schnell nachziehen kann. 5.2.3. SQL-Formatter Zur Verwendung in den Softwareschichten oberhalb der Datenbank gibt es eine Klasse, die wir SQL-Formatter genannt haben. In diesen Softwareschichten werden die Queries nicht von Hand ausformuliert, sondern der Formatter erzeugt die Einzelteile, die sich unter den eingesetzten Datenbanksystemen unterscheiden. Dies lohnt auch schon bei einfachen StringVergleichen, da der Formatter auch die Maskierung übernimmt. Beispiel: "Lastname = 'Meier'" Mit Formatter: Connection.SqlFormatter.Comparison("Lastname", "Meier", ValType.String) using System; using System.Collections; using VI.Base; using VI.DB; using VI.DB.Implementation; using VI.DB.Oracle; public class MyClass { public static void Main() { ISqlFormatter mssql = new MicrosoftSqlFormatter(); ISqlFormatter oracle = new OracleSqlFormatter(); // Beispiel für ein Statement WL("Plain", "select * from Person where Lastname = 'Meier'"); // Formatiert für MS SQL WL("1. MS SQL", "select * from Person where " + mssql.Comparison("Lastname", "Meier", ValType.String)); // Und Oracle WL("1. Oracle", "select * from Person where " + oracle.Comparison("Lastname", "Meier", ValType.String)); // Mit Hochkommas WL("2. MS SQL", "select * from Person where " + mssql.Comparison("Lastname", "O'Donnell", ValType.String)); WL("2. Oracle", "select * from Person where " + oracle.Comparison("Lastname", "O'Donnell", ValType.String)); // Unicode WL("3. MS SQL", "select * from Person where " + mssql.Comparison("Lastname", "\u0425\u0440\u0443\u0449\u0451\u0432", ValType.String)); WL("3. Oracle", "select * from Person where " + oracle.Comparison("Lastname", "\u0425\u0440\u0443\u0449\u0451\u0432", ValType.String)); // Aufruf einer Stored Procedure WL("4. MS SQL", mssql.StoredProcedure( "TestProc", mssql.FormatValue("Test", ValType.String, true), mssql.FormatValue(42, ValType.Int, true))); WL("4. Oracle", oracle.StoredProcedure( "TestProc", oracle.FormatValue("Test", ValType.String, true), oracle.FormatValue(42, ValType.Int, true))); } public static void WL(string prefix, string mssql, string oracle) { Console.WriteLine("{0}:", prefix); Console.WriteLine("MS SQL:\t" + mssql); Console.WriteLine("Oracle:\t" + oracle); Console.WriteLine(); } } Da der Formatter nur Teile von Statements formatiert, kann man komplexe Statements nach Systemen getrennt in einer Resource-Datei hinterlegen und nur Vergleiche gegen dynamische Werte per Formatter einfügen. 5.3. Frontend – Ebene Das Frontend soll sowohl als Fat-Client laufen als auch als Thin-Client im Web. Wir haben insgesamt über 500 Tabellen im Datenmodell, zu jeder Tabelle muß es Formulare geben, mit denen die Daten bearbeitbar werden. Dazu kommt noch eine Menge an Zuordnungs- und Übersichtsformularen. Diese Formulare in zwei verschiedenen Systemen zu bauen, hätte unsere Kapazitäten gesprengt. Unser Ziel war demzufolge ein Compilat für alle zu erhalten. Wir haben diese Zielstellung so erreicht, indem wir Layout und Funktionen strikt getrennt haben. Ein Frontend besteht immer aus 2 Bestandteilen, der Darstellung und dem dahinter liegenden Code. Die Darstellung ist z.B. die Definition eines Buttons, der Code der dazugehörige Click-Eventhandler. Die Darstellung wird durch eine bei uns entwickelte Engine aus einer in XML hinterlegten Beschreibung gerendert. Der Code liegt als DLL bei und spricht die jeweiligen Frontend-Controls über Schnittstellen an. Für jedes Control gibt es eine Fat- und eine Web-Client-Implementierung. Der Fat-Client basiert auf Windows-Forms, d.h. wir haben die bestmögliche Integration in die Windows-Umgebung. Er läuft derzeit nicht unter Mono, da nicht portable Fremdcontrols verwendet wurden. Der Web-Client besitzt ein eigenes Control-Set, welches dieselben Interfaces wie der Fat-Client implementiert. Die Kommunikation mit dem Server erfolgt über Javascript. Das ermöglicht eine Aktualisierung der Control-Inhalte ohne eine kompletten Roundtrip für die angezeigte Seite. Einen ersten Prototyp dieser Lösung hatten wir 2001 gebaut. Heute ist diese Art der Kommunikation allgemein als “Ajax“ bekannt. Damit ist das Problem der Nutzer-Interaktion gelöst. Wenn ein Wert geändert wird (z.B. der Nachname einer Person) so ändert sich direkt ein anderer davon abhängiger Wert (z.B. die EMail-Adresse). Diese Änderung soll dem Nutzer immer sofort angezeigt werden. Die Navigation ist in der Datenbank hinterlegt und wird durch die jeweilige Engine interpretiert. Für den jeweiligen Kunden an seine Bedürfnisse anpaßbar. Zum Schluß noch einen kurzen Blick auf die Statistik. Der gesamte Quelltext von ActiveEntry ohne Dokumentation und ohne kundenspezifische Anpassungen umfaßt 162 MB. Die einzelnen Bestandteile wurden klassifiziert nach den 3 Bereichen - allgemein gültig - Meta-Programmierung - Doppelimplementierung Die beste Nachnutzung haben wir auf der Objektebene, da handelt es sich nur um ein paar Prozent, die doppelt implementiert werden mußten und deswegen keiner weiteren Beachtung benötigen. Viele Quellen sind hier allgemein gültig, zumal die Objektebene auch vom Gesamtvolumen her das Größte ist. Im Frontend ist uns das nicht ganz so gut gelungen. Wir haben 7 MB Quelltext im Frontendbereich als Doppelimplementierung, das sind vor allem die Controls für Fat-Client und die Controls für Thin-Client. Softwareebene Doppelt implementiert Allgemeingültig Auf MetaEbene Gesamtergebnis DBLayer 11.280.750 9.352.411 5.663.247 26.296.408 Object 4.601 74.243.447 Frontend 7.782.746 20.984.713 74.248.048 20.469.139 49.236.598 Tools 1.115.490 1.115.490 Unit 17.362 Gesamt: Summe 19.085.459 von Byte 11.522.995 11.540.357 117.219.056 26.132.386 162.436.901 Lines of Code ist die Meßgröße, mit der üblicherweise hantiert wird. Insgesamt haben wir inzwischen 3,4 Millionen Zeilen erstellt. Mit Dokumentation und kundenspezifischen Projekten, die wir im Laufe der Jahre gebaut haben, sind es noch einmal so viel, also insgesamt fast 7 Millionen Quelltextzeilen. Softwareebene Doppelt implementiert Allgemeingültig Auf MetaEbene Gesamtergebnis DBLayer 320.673 215.765 171.775 708.213 Object 171 1.215.790 Frontend 247.561 593.827 1.215.961 462.788 1.304.176 Tools 34.110 34.110 Unit 516 Gesamt: Summe 568.921 von Lines 209.805 210.321 2.269.297 634.563 3.472.781 Am spannendsten scheint jedoch die Zusammenstellung nach Prozenten zu sein. Die Datenbankschicht hat 16 % Anteil am Gesamtprodukt. In diesem Bereich haben wir aufgrund der SQL-Unterschiede die schlechteste Quote der Allgemeingültigkeit erreicht, aber immerhin mit Meta-Ebene und Allgemeingültigkeit trotz der großen Differenzen zwischen den SQL-Dialekten nur 42 % doppelt entwickelt. Bei den Frontends haben wir mit 80 % Allgemeingültigkeit eine passable Quote erreicht. Spezielle Buildtools, welche im Daily-Build-Prozess gebraucht werden, haben wir vollständig allgemeingültig und bei den Unit-Tests sind es auch nahezu 100% Softwareebene Doppelt implementiert Allgemeingültig Auf MetaEbene Anteil am Gesamtprodukt DBLayer 42,9% 35,6% 21,5% 16,2% Object 0,0% 100,0% Frontend 15,8% 42,6% Tools 45,7% 41,6% 30,3% 100,0% 0,7% 7,1% Unit 0,2% 99,8% Gesamtprodukt 11,7% 72,2% 16,1% 100,0%