Synchronisation von Trainingsdaten
Transcrição
Synchronisation von Trainingsdaten
Leopold-Franzens-Universität Innsbruck Institut für Informatik Forschungsgruppe Quality Engineering Synchronisation von Trainingsdaten Bachelorarbeit eingereicht bei Univ.-Prof. Dr. Ruth Breu Andreas Grill Thomas Juen Innsbruck, 18. September 2009 Vorwort 1 Motivation Unser Auftraggeber InfPro IT Solutions GmbH entwickelte vor einigen Jahren zusammen mit der Firma SP Sportdiagnosegeräte GmbH ein System zur sportartspezifischen Trainingsplanung und –steuerung. Diese Software findet ihren Einsatz derzeit zum Großteil im Spitzensportbereich und erleichtert Coaches die Planung, Analyse und vor allem Verteilung von Trainingsplänen an Athleten und Athleten-Gruppen. Die Version 4 des Trainingstimers (so lautet der Name des Produktes) persistiert die Daten in allen Lizenzmodellen (Trainer, Athlet, …) in einer lokalen Microsoft Access Datenbank und bietet über ein Synchronisationsmodul die Möglichkeit Daten auszutauschen. Derzeit entsteht aus diversen Gründen eine komplett überarbeitete und erweiterte Version der Software, mit dem Namen Trainingstudio. Diese wird nicht mehr mit einem einzigen Datenbanksystem auskommen, da neben der lokalen Datenhaltung (hierfür wird das Datenbanksystem Microsoft SQL CE zum Einsatz kommen) auch eine zentrale Online-Datenbank (Microsoft SQL Server) geplant ist. Ziel unseres Projektes war es, ein Synchronisationskonzept auszuarbeiten, welches unabhängig vom verwendeten Datenbanksystem eingesetzt werden kann. Darüber hinaus zählte auch die Implementierung des Konzeptes in Form einer Programmierschnittstelle (API) und die konfigurationslose Einbindung in das Trainingstudio zu unseren Aufgaben. 2 Abstract Several years ago InfPro IT Solutions GmbH developed a system for sport intrinsic scheduling and controlling in collaboration with SP Sportdiagnosegeräte GmbH. This software is mainly used in the domain of top-class sports and makes the Vorwort 4 planning and analytic phases easier but primarily the distribution of plans to athletes and groups of athletes. Version 4 of this software called Trainingstimer stores the data of all possible license-variants in a local Microsoft Access Database and uses a synchronization module for providing the possibility of exchanging data. For various reasons a complete revised and extended version of the software with the new name Trainingstudio is currently under development. The new version uses a more sophisticated system for data storage. In addition to a local database (this time Microsoft SQL CE is used) a central database server (Microsoft SQL Server) is a planned feature. The aim of this project was to create a synchronization concept, which can be used independently of the underlying database system. Beyond that, we also had to implement the concept in terms of a programming interface (API) and integrate an initial support in the Trainingstudio software. 3 Danksagung Im Laufe der Projektarbeit standen uns viele helfende Hände mit Rat und Tat zur Seite. Besonders bedanken möchten wir uns bei: Dipl.-Ing. Hansjörg Haller für die technische Betreuung, die unzähligen Beratungsstunden und die geduldige Art und Weise den Projektfortschritt konstant aufrecht zu erhalten. Prof. Dr. Ruth Breu für ihre Betreuung und Unterstützung. Ing. Thomas Schliernzauer und Dr. Harald Pernitsch der Firma SP Sportdiagnosegeräte GmbH für ihre Unterstützung. Frau Jasmin Karner für den raschen Review der Dokumentation. Unseren Familien und Freunden für ihre Hilfe und Unterstützung. Inhaltsverzeichnis Vorwort ................................................................................................................... 3 1 Motivation ............................................................................................ 3 2 Abstract................................................................................................. 3 3 Danksagung .......................................................................................... 4 Inhaltsverzeichnis .................................................................................................... 5 Einleitung ................................................................................................................ 9 4 Anforderungen ...................................................................................... 9 5 Technische Umgebung ....................................................................... 10 6 Umsetzung .......................................................................................... 11 7 Auswahl der Komponenten ................................................................ 12 8 7.1 Wahl des Betriebssystems ...................................................... 12 7.2 Wahl der Programmiersprache ............................................... 12 7.3 Wahl des Persistenz-Frameworks .......................................... 12 7.4 Wahl der Entwicklungsumgebung ......................................... 13 7.5 Wahl sonstiger Komponenten ................................................ 13 Ergebnis & Ausblick .......................................................................... 13 Pflichtenheft .......................................................................................................... 15 9 Aktuelle Situation ............................................................................... 15 10 EDV Technische Voraussetzungen .................................................... 15 11 Geschäftsprozessmodell ..................................................................... 16 12 Anwendungsfälle ................................................................................ 16 Inhaltsverzeichnis 6 Softwarearchitektur ............................................................................................... 19 13 Begriffserklärungen ............................................................................ 19 14 Softwareverteilung ............................................................................. 20 15 16 17 14.1 ThemiSync-Erweiterte IBOF-Applikation ............................. 20 14.2 Applikationsdatenbank ........................................................... 20 14.3 Transportdatenbank ................................................................ 20 14.4 Grafischer Überblick der Softwarekomponenten ................... 21 Technologiekonzept ........................................................................... 21 15.1 Systemaufbau ......................................................................... 22 15.2 Spezielle Technologien .......................................................... 24 15.3 Synchronisation ...................................................................... 27 Logische Sicht .................................................................................... 39 16.1 Komponentenarchitektur ........................................................ 39 16.2 Querschnittskomponente ........................................................ 47 16.3 Anwendungskern .................................................................... 48 Implementierungssicht ....................................................................... 54 17.1 Initialisierung ......................................................................... 54 17.2 Metadaten ............................................................................... 60 17.3 Konfiguration ......................................................................... 67 17.4 Synchronisation ...................................................................... 71 Qualitätssicherung ................................................................................................. 91 18 Analyse ............................................................................................... 92 19 Entwurf ............................................................................................... 92 20 Implementierung................................................................................. 93 20.1 Extreme Programming (XP) .................................................. 93 20.2 Codereviews ........................................................................... 94 Inhaltsverzeichnis 7 20.3 Pair-Programming .................................................................. 94 20.4 Unittests.................................................................................. 94 20.5 Cruisecontrol .......................................................................... 94 21 Integration........................................................................................... 95 22 Einsatz & Wartung ............................................................................. 95 Benutzerhandbuch ................................................................................................. 97 23 Einleitung ........................................................................................... 97 24 Beispielapplikation ............................................................................. 97 24.1 Einleitung ............................................................................... 97 24.2 Benötigte DLLs ...................................................................... 98 25 ThemiSync Konfigurationstool .......................................................... 99 26 Vorbereitungen (Datenbank, IBOF) ................................................. 100 27 26.1 Datenbank ............................................................................ 100 26.2 IBOF ..................................................................................... 103 Konfiguration (ThemiSync) ............................................................. 106 27.1 Exportkonfiguration (ExportConfigurationEntity) .............. 107 27.2 Importkonfiguration (ImportConfigurationEntity) .............. 108 27.3 Konfigurationsgruppe (ConfigurationGroupEntity) ............ 110 27.4 Konfigurationsgruppen-Zuordnung (ConfigurationGroupMappingEntity) ............................................... 110 28 27.5 Entitätstyp (EntityTypeEntity) ............................................. 110 27.6 Beispielapplikation – ThemiSync Konfiguration................. 111 API-Schnittstellen............................................................................. 115 28.1 ThemiSyncBase .................................................................... 116 28.2 ThemiSyncConfig ................................................................ 117 28.3 ThemiSyncExport ................................................................ 117 Inhaltsverzeichnis 28.4 8 ThemiSyncImport ................................................................ 118 Abbildungsverzeichnis ........................................................................................ 121 Literaturverzeichnis............................................................................................. 123 Einleitung 4 Anforderungen Die Firma InfPro IT Solutions GmbH entwickelt und vertreibt zusammen mit der Firma SP Sportdiagnosegeräte GmbH den Trainingstimer - eine Software zur Planung von sportartspezifischen Trainingseinheiten. In der aktuellen Version besteht bereits die Möglichkeit Trainingspläne und sonstige Daten zwischen Trainern und Athleten zu synchronisieren. Hier gibt es allerdings neben Performanceproblemen auch diverse andere Gründe, welche ein neues Synchronisationskonzept erforderlich machen. Im Zuge eines groß angelegten aktuellen Relaunchs der Software welche dann unter dem Namen Traininstudio vermarktet wird, soll ein solches neues Konzept zum Einsatz kommen. Das ist die Grundlage für die Entstehung dieses Projektes, welches konkretisiert folgende Anforderungen stellt: Synchronisationskonzept Die grundsätzliche Anforderung besteht darin ein Konzept auszuarbeiten, welches die Synchronisation zwischen beliebig vielen Trainingstudio-Instanzen ermöglicht. Dabei ist es von großer Bedeutung, dass Konflikte verlässlich erkannt werden, während konfliktfreie Datenänderungen ohne weiteres Zutun abgeglichen werden. Weiters muss das Konzept in Form einer API implementiert werden und diese in seiner Grundfunktionalität (ohne endgültige Konfiguration) in das Trainingstudio integriert werden. Flexible Konfiguration Die Art beziehungsweise Struktur der synchronisationsrelevanten Daten ist zur Zeit der Systementwicklung nicht bekannt und muss daher flexibel konfigurierbar sein. Einleitung 10 Datenbanksystemunabhängigkeit Die Daten des Trainingstudio werden derzeit für jede Instanz lokal in einer Mircosoft SQL CE Datenbank persistiert. Da es aber Firmen-intern bereits Überlegungen zu einer globalen Trainingsdatenbank für die gesamte TrainingstudioCommunity gibt muss davon ausgegangen werden, dass in naher Zukunft auch zwischen verschiedenen Datenbanksystemen synchronisiert werden muss. Synchronisationsdatenübertragung Erfahrungswerte der Firma InfPro IT Solutions GmbH besagen, dass vor allem im Spitzensportbereich oft an sehr exotischen Orten trainiert wird. Aus diesem Grund darf nicht davon ausgegangen werden, dass für die Übertragung der Synchronisationsdaten Internet verwendet werden kann. Trotzdem muss diese Möglichkeit im Konzept vorgesehen werden. Rollenkonzept Im Trainingstudio wird es grundsätzlich zwei Benutzergruppen geben – Trainer und Athleten. Das Synchronisationssystem muss die Möglichkeit bieten, differenzierte Synchronisationsabläufe zu konfigurieren um eine Berechtigungshierarchie umzusetzen. Damit sollen unter anderem per Konfiguration richtige, aber für die Applikation irrelevante Synchronisationskonflikte automatisiert aufgelöst werden. Datensicherheit Bereits die aktuelle Version des Trainingstimers ist in verschiedenen Sportvereinen verschiedener Länder im Einsatz. Die Trainingspläne der Vereine sind also zum Teil sehr sensible Daten und dürfen unter keinen Umständen an ein unvorhergesehenes Ziel synchronisiert werden. Deshalb muss für den Transfer der Synchronisationsdaten ein Sicherheitskonzept eingesetzt werden. 5 Technische Umgebung Um eine höchstmögliche Kompatibilität mit dem Trainingstudio in Version 1.0 der Firma InfPro zu erzielen, orientierten wir uns an Technologien welche dort bereits Verwendung gefunden haben. Dazu zählt die Programmiersprache C# 2.0 und das Einleitung 11 Microsoft .Net Framework 2.0. Weiters verwendeten wir – gleich wie das Trainingstudio – IBOF1 (Version 3.0) als Persistenz-Framework. Als Transfermedium verwendeten wir die Microsoft SQL CE Datenbank (Version 2.0), welche über IBOF angesteuert werden kann. 6 Umsetzung Kernstück der Umsetzung ist die Erweiterung der Software Trainingstudio. Dabei gilt es eine Möglichkeit zu schaffen um diverse Daten, in erster Linie Trainingspläne, zwischen beliebig vielen Trainingstudio-Softwareinstanzen abzugleichen. Einer der häufigsten Fälle der eine Synchronisation verlangt ist die Verteilung eines Trainingsplans, der von einem Trainer für einen oder mehrere Athleten erstellt wurde. Um ein, für den Trainer nützliches Feedback zum Trainingserfolg der Athleten zu erhalten, wird im Normalfall der Athlet seine durchgeführten und zum Teil veränderten Trainingsdaten zurücksynchronisieren. Zusätzlich soll auch ein Austausch von diversen Übungs- beziehungsweise Trainingseinheiten-Vorlagen unter Trainern, sowie die Verteilung von Terminen, Perioden und Tagesinformationen möglich sein. Bei der Umsetzung wurde gemäß der Anforderung darauf geachtet, dass der gesamte Synchronisationsprozess direkt, lokalitätsunabhängig und ohne weitere Zwischenkomponenten (z.B. Synchronisationsserver) möglich ist. Ein OnlineDatenabgleich ist über eine Erweiterung (Serverinstanz) vorgesehen und somit leicht realisierbar, jedoch ist aufgrund der teilweise exotischen Trainingslokalitäten der Athleten eine Peer-To-Peer Synchronisation vorrangig und somit fixer Bestandteil der Umsetzung. InfPro baut einen Großteil seiner Projekte, darunter auch das Trainingstudio, auf dem Firmeneigenen Persistenz-Framework IBOF auf. Aus diesem Grund war es wünschenswert und eine zusätzliche Herausforderung ein Konzept zu erarbeiten, 1 IBOF = InfPro Business Object Framework (Eigenentwicklung der Fa. InfPro) 2 „ThemiSync“ ist die Bezeichnung der Synchronisations-API welche im Zuge des hier Einleitung 12 welches keine direkte Abhängigkeit zum Produkt Trainingstudio hat, sondern generisch für alle IBOF-basierenden Projekte als Erweiterung eingesetzt werden kann. Da IBOF bereits sehr viele der benötigten Daten für eine generische Umsetzung des Synchronisationskonzepts zur Verfügung stellt, bot sich eine solche an und wurde zur Gänze realisiert. 7 Auswahl der Komponenten Die Komponenten, welche bei der Realisierung des Projektes ThemiSync2 zum Einsatz kamen waren zum Teil vom Auftraggeber vorgegeben oder wurden vom Projektteam ausgewählt. Die Gründe für die Auswahl beziehungsweise Verwendung der jeweiligen Komponenten seien im Folgenden genannt: 7.1 Wahl des Betriebssystems Da die Firma InfPro IT Solutions einen Großteil Ihrer Produkte für Windows basierende Betriebssysteme entwickelt (auch das Trainingstudio ist nur für Windows-OSs geeignet) war die Entscheidung des Betriebssystems mehr oder weniger bereits vorgegeben. Bei der Implementierung wurde Windows XP SP 3 verwendet. 7.2 Wahl der Programmiersprache Die Software Trainingstudio - und auch ein Großteil der anderen Produkte der Firma InfPro - wurde in der Programmiersprache C# implementiert. Um zum Einen möglichst kompatibel zu bleiben und zum Anderen eine Firmeninterne Weiterentwicklung von ThemiSync möglichst einfach zu halten, entschieden auch wir uns für diese Programmiersprache. Es wurde Microsoft C# in der Version 2.0 verwendet. 2 „ThemiSync“ ist die Bezeichnung der Synchronisations-API welche im Zuge des hier dokumentierten Projektes entstand. Es ist eine Zusammensetzung der Wörter „Themis“ (griech. Göttin der Gerechtigkeit, Ordnung und Philosophie) und „Synchronisation“ Einleitung 7.3 13 Wahl des Persistenz-Frameworks Als Persistenz-Framework wurde uns von InfPro das Firmeneigene Framework IBOF zur Verfügung gestellt. Dieses eignete sich besonders gut, da es bereits sehr viel Funktionalität bereitstellte und zusätzlich noch während der Entwicklungszeit beliebig erweitert werden konnte und auch wurde. 7.4 Wahl der Entwicklungsumgebung Microsoft bietet für die Programmierung im .Net Framework eine umfangreiche Entwicklungsumgebung. Visual Studio wurde für die Implementierung von ThemiSync in der Version v9 SP1 eingesetzt, da es die Standardsoftware ist und bereits im Vorfeld gute Erfahrungen damit gemacht wurden. 7.5 Wahl sonstiger Komponenten Für die Realisierung von diversen ThemiSync-Funktionalitäten wurden teilweise Komponenten von Dritten verwendet. Dazu zählen Folgende: SharpZipLib SharpZipLib 0.8 ist eine Klassenbibliothek, welche diverse Funktionen für den Umgang mit komprimierten Dateien bietet. Die Entscheidung fiel auf diese Komponente, da sie sehr umfangreich ist und zudem der GNU General Public License unterliegt. NUnit NUnit ist ein Framework für den Einsatz von Unittests bei der Softwareentwicklung. Für ThemiSync wurde NUnit 2.4 verwendet, da es auch in der Firma InfPro eingesetzt wird. NVelocity NVelocity ist ein Werkzeug um zur Laufzeit dynamisch auf Objekte zuzugreifen. Es ist ein Port der Open Source Java Template Engine „Velocity”. Da keine alternative Software mit der gewünschten Funktionalität gefunden wurde, war diese Entscheidung klar. Einleitung 8 14 Ergebnis & Ausblick Zusammenfassend wurde ThemiSync zu einem Synchronisationswerkzeug, welches sehr flexibel eingesetzt werden kann. Der generische Ansatz und die direkte Integration in den IBOF-Generator ermöglichen eine sehr einfache Erweiterung aller bestehenden beziehungsweise neuen IBOF-Softwareprojekte. Damit kann über wenige Konfigurationsschritte die geforderte Synchronisation von TrainingstudioDaten umgesetzt werden und zusätzlich können die verschiedensten Szenarien, die einen Datenabgleich zwischen zwei oder mehreren Datenbanken erfordern umgesetzt werden. ThemiSync ist bereits in das Trainingstudio integriert und wurde von der Firma InfPro IT Solutions für den endgültigen Einsatz konfiguriert. Die API wird in Kürze diversen Live-Tests unterzogen. Das Resultat des Projektes ist sehr generisch einsetzbar und bietet viele Schnittstellen für diverse Erweiterungen. Aus diesem Grund ist ThemiSync für zukünftige Projekte der Firma InfPro IT Solutions eine solide Basis wenn es um die Realisierung von Synchronisationsszenarien geht. Es bleibt zu hoffen, dass die API für die Firma InfPro IT Solutions lange nützlich sein wird. Pflichtenheft 9 Aktuelle Situation Die Firma InfPro IT Solutions GmbH entwickelt zusammen mit der Firma SPSport GmbH seit einigen Jahren eine Softwarelösung, welche als Planungs- und Steuerinstrument für Trainingskonzepte im Spitzensport-Bereich dient. Konkret ermöglicht diese Software, der Trainingstimer, Trainingspläne zu erstellen und diese an Athleten-Gruppen zu verteilen. Diese genannte Verteilung wird bereits bei der aktuellen Trainingstimer-Version über Synchronisationsprozesse realisiert, weist allerdings einige Schwachpunkte auf. Für die aktuell entstehende Relaunch-Version des Trainigstimers mit dem Namen Trainingstudio soll auch eine Neuentwicklung dieses Synchronisationsprozesses realisiert werden, was die Aufgabe dieser Projektarbeit ist. Die neue Synchronisationslösung soll im Gegensatz zur Aktuellen objektorientiert und transaktionssicher sein. 10 EDV Technische Voraussetzungen .Net 2.0 – Kompatibles Betriebssystem. Entsprechende Umgebung, damit Trainingstudio lauffähig ist. IBOF – Kompatibles Datenbanksystem für Quell- und Zieldatenbank. IBOF – Kompatibles Datenbanksystem für Transport-Container3. Übertragungsmedium für die Synchronisationsdaten (z.B.: USB-Stick, Internet, …). 3 Medium um die Synchronisationsdaten von der Quell- zur Zieldatenbank zu übertragen. Pflichtenheft 11 16 Geschäftsprozessmodell In folgender Abbildung 1 wird ein Überblick über den Ablauf allgemeiner Synchronisationsvorgänge mit ThemiSync dargestellt. Applikation 1 (Quelle) Synchronisation Selektion der zu exportierenden Daten aus der Quellreplica (Anhand von Meta- und Konfigurationsdaten) Speichern dieser Daten im Transport-Container Applikation 2 (Ziel) Transport der Daten (Transport-Container) Selektion der zu importierenden Daten aus dem Transport-Container (Anhand von Konfigurationsdaten) Speichern dieser Daten in der Zielreplica (Konfliktbehandlung) Abbildung 1: Ablauf allgemeiner Synchronisationsvorgang 12 Anwendungsfälle In der folgenden Abbildung 2 werden die Anwendungsfälle von ThemiSync visualisiert: Pflichtenheft 17 Konfigurieren Exportieren User Importieren Abbildung 2: Anwendungsfälle Da ThemiSync eine vielseitig verwendbare Synchronisations-API ist, werden in der Abbildung 2 die Anwendungsfälle nur allgemein visualisiert. Diese Anwendungsfälle können allerdings vielfältige Gestalt annehmen. Im Trainingstudio beispielsweise kann ein Trainer mehrere Trainings-Pläne für seine Athleten exportieren. Die Athleten können nun jeweils ihren persönlichen Plan importieren und gegebenenfalls in abgeänderter Form erneut für den Trainer exportieren. Softwarearchitektur 13 Begriffserklärungen Zum besseren Verständnis seien vorab folgende Begriffe erläutert: Replica Der Begriff Replica bezeichnet einen Datenspeicher beliebiger Art, wobei es sich im Rahmen von ThemiSync ausschließlich um ein IBOF-kompatibles Datenbank Management System handelt. Metadaten Metadaten sind Zusatzinformationen zu Entitäten, die ThemiSync über konkrete Datensätze mitverwaltet. Hashcode Ein Hashcode ist die Summe über bestimmte Attribute einer Entity. Er wird nach einem bestimmten Algorithmus berechnet und ergibt bei identen Attributwerten immer das gleiche Ergebnis. Ein Hashcode ermöglicht ein effizientes Vergleichen von analogen Datensätzen der Quell- beziehungsweise Zieldatenbank. Entität Eine Entität ist eine persistierte Objektinstanz, welche je nach Geschäftsmodell-Hierarchie aus einem oder mehreren Datensätzen bestehen kann. Transport-Container Als „Transport-Container“ wird das resultierende Medium eines ThemiSync Exports bezeichnet. Dieser Container enthält alle für den Import bestimmten Synchronisationsdaten, welche nach Synchronisationsgruppen (siehe 16.1.2) aufgeteilt sind. C# Reflection Reflection ist eine Technologie, welche neben diversen anderen Programmiersprachen von allen im .Net-Framework einsetzbaren Sprachen – Softwarearchitektur 20 darunter auch C# - angeboten wird. Sie ermöglicht es, zur Laufzeit auf diverse Informationen zu Klassen beziehungsweise deren Instanzen zuzugreifen. Mit dem Einsatz von Reflection wird eine sehr hohe Laufzeitflexibilität erreicht, allerdings müssen dafür Einbußen bei der Ausführungsgeschwindigkeit in Kauf genommen werden. 14 14.1 Softwareverteilung ThemiSync-Erweiterte IBOF-Applikation Die ThemiSync API vereint sowohl Export- als auch Import-Funktionalität in einem Softwarepaket und kann sämtliche IBOF Projekte um die Synchronisationsfähigkeit erweitern. Für den sinnvollen Einsatz benötigt es mindesten zwei Softwareinstanzen, welche auf denselben oder kompatiblen Datenbankmodellen aufbauen. 14.2 Applikationsdatenbank Hierfür können alle IBOF-kompatiblen Datenbanksysteme zum Einsatz kommen. In dieser Datenbank werden sowohl applikationsspezifische Daten gespeichert, als auch von ThemiSync generierte und benötigte Metadaten persistiert. 14.3 Transportdatenbank Standardmäßig wird für den Transfer der Synchronisationsdaten das filebasierte Datenbanksystem Microsoft SQL Server Compact verwendet, allerdings ermöglicht ThemiSync durch vordefinierte Schnittstellen beliebige andere IBOF-kompatible Transportmedien einzusetzen. Softwarearchitektur 14.4 21 Grafischer Überblick der Softwarekomponenten Folgende Abbildung 3 stellt die Abhängigkeit der Softwarekomponenten grafisch dar: ApplikationsDatenbank ThemiSync Instanz Transport Datenbank Abbildung 3: Softwareverteilung 15 Technologiekonzept In diesem Abschnitt gehen wir im Detail auf die einzelnen Komponenten und die verwendeten Technologien ein. Weiters wird hier ein Überblick über spezifischere Synchronisierungsabläufe gegeben, welche anhand von Beispielen verdeutlicht werden. Softwarearchitektur 15.1 22 Systemaufbau IBOF ApplikationsInstanz ApplikationsInstanz ThemiSync Export Modul ThemiSync Import Modul DBMS IBOF DBMS Exportvorgang Importvorgang Transfermedium TransportContainer DB DB ... DB Abbildung 4: Systemaufbau Im folgenden Abschnitt erhalten wird ein Überblick über die wichtigsten Komponenten eines Systems, welches ThemiSync zur Datensynchronisation verwendet gegeben. Abbildung 4 illustriert einen grafischen Überblick über den Aufbau eines solchen Systems. 15.1.1 Applikationsinstanz Die Applikationsinstanzen sind Softwarelösungen, welche auf unterschiedlichen physikalischen Rechnern laufen können und in den synchronisierbaren Bereichen kompatible Datenbankstrukturen besitzen. Dabei ist die Anzahl der Instanzen theoretisch beliebig. Die Persistenzschicht einer jeden Applikationsinstanz muss auf IBOF aufbauen, welches ab der Version 3.0.0.124 ThemiSync vollständig unterstützt. Softwarearchitektur 23 In den Applikationsinstanzen werden die Synchronisierungsprozesse angestoßen und Synchronisationskonflikte beziehungsweise Spezialbehandlungen verarbeitet. 15.1.2 ThemiSync Export Modul Das ThemiSync Export Modul ist ein fixer Bestandteil der Synchronisations-API und wird von der Applikationsinstanz angesteuert. Aufgabe dieses Moduls ist die Analyse der für die Synchronisierung relevanten Daten mit Hilfe spezieller Metadaten. Weiters erstellt das Export Modul für jeden atomaren Synchronisierungsvorgang eine Datei-basierte Datenbank, welche mit den Synchronisationsdaten befüllt wird. Eine beliebige Anzahl dieser Datei-basierten Datenbanken wird zu einem Transportcontainer zusammengefasst, was auch zu den Aufgaben des Export-Moduls zählt. 15.1.3 Transfermedium Für den Transport der Synchronisationsdaten kann ein beliebiges Medium verwendet werden. Als Beispiele seien erwähnt: USB-Stick, Email-Versand, oder Übertragung mittels WCF4. 15.1.4 ThemiSync Import Modul Das Import Modul als fixer Bestandteil von ThemiSync nimmt einen Exportcontainer entgegen und verarbeitet die enthaltenen Daten. Die Synchronisationsdaten im Exportcontainer werden mit dem Datenbestand der Zieldatenbank verglichen und dabei nötige Synchronisationsprozesse ausgelöst. An dieser Stelle können Synchronisationskonflikte auftreten, welche über registrierte Methoden aus der importierenden Applikationsinstanz entsprechend behandelt werden müssen. 4 Windows Communication Foundation Softwarearchitektur 15.2 15.2.1 24 Spezielle Technologien IBOF Das „InfPro Business Object Framework“ deckt mit seiner Funktionalität das gesamte Spektrum der von uns benötigten Interaktionen mit den Datenbankmanagement-Systemen ab. Ein wichtiger Bestandteil dieses Frameworks ist der IBOF Generator welcher unter anderem die Möglichkeit bietet, aus einem Datenbankmodell CRUD5-fähigen Code zu erstellen. Im Zuge dessen werden Zusatzinformationen zu jeder Klasse mitgeliefert, welche in ThemiSync Verwendung finden. Damit ist eine Verwendung von ThemiSync für eine nicht IBOF-kompatible Applikation nicht vorgesehen. Weiters wurde IBOF auch für ThemiSync-interne Abläufe verwendet, womit das Resultat einen höchstmöglichen Kompatibilitätsgrad mit IBOF-basierenden Applikationen erreicht. Folgende Tabelle beschreibt die generierten Klassen-Typen und deren Funktionalität. Klassentyp Merkmal Beschreibung DAC-Klassen - Im Ordner „DAC“ Die - …DAC.cs Classes“ generierten dienen „Data Access als Mittler zwischen Datenbank und IBOFbasierter Applikation. Für jeden im IBOF-Generator konfigurierten Typ mit dem aktiven Flag „Persist in DB“ wir eine DAC-Klasse generiert welche für alle Felder bereits eine FindBy-Methode bereitstellt und beliebig erweitert werden kann. 5 CRUD (Create-, Read-, Update-, Delete-Operationen) CRUD beschreibt die Grundfunktionalität der Persistenzschicht. Softwarearchitektur Entity-Klassen 25 - Im Ordner „Entities“ Für jeden konfigurierten Typ wird - …Entity.cs eine Entity-Klasse generiert. Diese stellen die eigentlichen Klassen des Geschäftsmodells dar. Instanzen davon können bei entsprechender Konfiguration direkt persistiert werden. Info-Klassen - Im Ordner „Info“ Die - …EntityInfo.cs enthalten in Form von Konstanten statischen Info-Klassen Informationen über Klassenname (Tabellenname) und Property- Bezeichnungen (Felder) der EntityKlassen. Damit lassen sich bequem DB-System unabhängige SQL- Queries erstellen. Test-Klassen - Im Ordner „UnitTests“ Für die automatisierte Überprüfung - …Test.cs der Grundfunktionalität der EntityKlassen, welche per Überschreibung diverser Methoden beeinflusst werden kann, werden vom IBOF Generator automatisch UnitTest-Klassen erstellt. 15.2.2 NVelocity NVelocity (Version 1.6) ist ein Port der Open Source Java Template Engine „Velocity” (entwickelt von der Apache Software Foundation) nach C# .Net. Diese Template Engine bietet sowohl lesenden und schreibenden Zugriff auf definierte Instanzattribute, als auch einfache Kontrollstrukturen über eine simple Skriptsprache. ThemiSync bedient sich dieser Library um die Konfiguration für den Entwickler über Vorlagen (Templates) möglichst einfach zu halten. Diese Vereinfachung kommt vor allem bei der Steuerung des Rollenkonzeptes zum Einsatz, ist aber so generisch Softwarearchitektur 26 gehalten, dass dem Entwickler auch benutzerdefinierte Abfragen zur Verfügung stehen. Die entsprechenden Attribute können direkt über die ThemiSync API registriert werden. Abbildung 5 illustriert die Zugriffsmöglichkeiten auf einen VelocityManager. ThemiSyncBase +GlobalVelocityManager : VelocityManager +<<get>> GetConfigurationGroupVelocityManager(in configurationGroup : ConfigurationGroupEntity) : VelocityManager 1 1 Global 1 ConfigurationGroup VelocityManager * ThemiSyncExport ThemiSyncImport Abbildung 5: VelocityManager Zugriffsmöglichkeiten 15.2.3 SharpZipLib SharpZipLib ist eine Open Source Klassenbibliothek, welche den Umgang mit Dateiarchiven im Vergleich zur nativen .Net-Implementierung erheblich vereinfacht und erweitert. ThemiSync verwendet SharpZipLib zum Erstellen beziehungsweise Einlesen des Transportcontainers, welcher eine beliebige Anzahl von Exportdatenbanken enthält. Eine Exportdatenbank enthält die Daten eines in sich abgeschlossenen Exportvorgangs. 15.2.4 NUnit NUnit ist ein Port von JUnit, ein Werkzeug zur Handhabung von Unit-Tests. Softwarearchitektur 15.2.5 27 ILMerge ILMerge ist ein Tool von Microsoft, welches das Zusammenfassen von mehreren Assemblies zu einem Paket ermöglicht. Wir verwenden dies um die gesamte Funktionalität von ThemiSync in einer einzigen DLL bereitstellen zu können. 15.3 Synchronisation In diesem Abschnitt wird das Herzstück von ThemiSync – das konkrete Synchronisationskonzept – im Detail beschrieben. 15.3.1 Synchronisations-Algorithmus Für dieses Projekt galt es ein Synchronisationskonzept zu erarbeiten, um Daten zwischen beliebig vielen Replicas automatisiert abzugleichen. Dabei kann nicht davon ausgegangen werden, dass die Replicas sich untereinander zur Gänze vertrauen können. Dadurch muss es eine Möglichkeit geben Synchronisationsdaten auf Entitätsebene zu filtern um nur erlaubte Daten für die Synchronisation freizugeben. Für ThemiSync wurde ein Algorithmus verwendet, welcher folgende Eigenschaften voraussetzt: Jede synchronisierbare Entität besitzt in den Metadaten sowohl einen Hash des aktuellen Objektstatus (CurrentHash6), einen sogenannten LastSyncHash7, welcher den Objektstatus nach der letzten Synchronisation repräsentiert und ein Flag8 LocallyChanged9, welches angibt ob Änderungen vorliegen die noch nicht exportiert wurden. Falls die Entität noch nie synchronisiert wurde, dann besitzt das Datenfeld LastSyncHash keinen Wert. 6 CurrentHash wird in den Grafiken mit CH abgekürzt. 7 LastSyncHash wird in den Grafiken mit LSH abgekürzt. 8 Variable mit zwei möglichen Werten (True beziehungsweise False). 9 LocallyChanged wird in den Grafiken mit LC abgekürzt Softwarearchitektur Diese drei Datenfelder 28 genügen bereits für diesen Algorithmus um Synchronisierungskonflikte zu erkennen und gegebenenfalls automatisiert zu beheben. Die Arbeitsweise des Algorithmus sieht wie folgt aus: Wenn eine Entität geändert wird und das Flag LocallyChanged den Wert False besitzt, dann wird der LastSyncHash mit dem alten Wert des Datenfeldes CurrentHash überschrieben und LocallyChanged auf True gesetzt. Ist LocallyChanged bereits auf True, so wird der LastSyncHash auf seinem Wert belassen. Das bedeutet, dass der LastSyncHash nur bei der ersten lokalen Änderung nach jedem Exportvorgang vom originalen CurrentHash überschrieben wird. Damit kann beim Importvorgang eindeutig entschieden werden, ob der Objektstatus auf beiden Seiten verändert wurde, oder nur in der Quell-Replica. Das Flag LocallyChanged trägt also entscheidend zur Minimierung von Konflikten bei. Um die Arbeitsweise zu verdeutlichen wird diese anhand von Pseudo-Code im folgenden Abschnitt nochmals beschrieben: PROCEDURE OnEntityChanged ARGUMENTS entity : the entity object which was changed. BEGIN IF entity.LocallyChanged = False THEN entity.LastSyncHash := entity.CurrentHash entity.LocallyChanged := True ENDIF entity.CurrentHash := the new hashcode of the entity. END Export: Beim Exportieren wird für jede Entität der Synchronisationsdatenmenge eine Kopie in den Transport-Container erstellt, und anschließend das Flag LocallyChanged in der Quell-Replica auf False gesetzt. Import: Für jede Entität im Transport-Container wird überprüft, ob diese bereits in der ZielReplica existiert. Falls die Entität neu ist, wird sie eingefügt, andernfalls wird sie bei Gleichheit des CurrentHashs ignoriert. Softwarearchitektur 29 Unterscheiden sich allerdings die Hashcodes wird überprüft, ob der LastSyncHash der Entität in dem Transport-Container mit dem CurrentHash der analogen Entität in der Ziel-Replica übereinstimmt. Wenn dies der Fall ist, werden die Änderungen der Entität in die Ziel-Replica übernommen. Ansonsten wurde ein Konflikt entdeckt und die Konfliktbehandlung wird angestoßen. Wenn eine Entität importiert wird, so wird dessen Flag LocallyChanged in der Ziel-Replica auf False gesetzt. Um die Arbeitsweise des Algorithmus beim Importieren zu verdeutlichen wird diese im Folgenden mittels Pseudo-Code erneut beschrieben: PROCEDURE Import ARGUMENTS entityLst : A list of entities that are in the export container (source database) and might get imported. BEGIN doImport := False FOR entity entityLst IF entity exists in the destination database READ old entity from the destination database AS oldEntity IF entity.CurrentHash oldEntity.CurrentHash THEN IF entity.LastSyncHash = oldEntity.CurrentHASH THEN doImport := True ELSE READ from user defined conflict handling AS doImport ENDIF ENDIF ELSE doImport := True ENDIF IF doImport = True THEN IMPORT entity to the destination database entity.LocallyChanged := False ENDIF ENDFOR END Folgende Beispiele in Abbildung 6 bis Abbildung 9 veranschaulichen den Synchronisationsalgorithmus grafisch in verschiedenen Szenarien: Softwarearchitektur 30 Einfaches Synchronisations-Beispiel - Variante 1 Replica 1 Transport-Container Replica 2 Neue Entität A wird gespeichert A:ChangeTrackingEntity CH=1, LSH=null, LC=T A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=1, LSH=null, LC=F CH=1, LSH=null Replica 2 ist leer. A wird importiert A:ChangeTrackingEntity CH=1, LSH=null, LC=F A wird geändert A:ChangeTrackingEntity CH=2, LSH=1, LC=T A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=2, LSH=1 CH=2, LSH=1, LC=F A wird importiert A:ChangeTrackingEntity CH=2, LSH=1, LC=F Abbildung 6: Einfaches Synchronisations-Beispiel Variante 1 Softwarearchitektur 31 Das Beispiel aus Abbildung 6 beschreibt einen einfachen Synchronisationsablauf mit zwei Replicas. Zu Beginn wird in der Replica 1 eine neue Entity (A) erstellt. Dabei wird der CurrentHash über die Attributwerte berechnet und der LastSyncHash mit NULL initialisiert. Nach dem Exportvorgang von Replica 1 wird das Flag LocallyChanged auf False gesetzt um festzuhalten, dass diese Entität in ihrem aktuellen Zustand exportiert wurde. Auf Seite der Replica 2 wird während des Importvorganges festgestellt, dass keine analoge Entität existiert. Sie wird neu erstellt und das Flag LocallyChanged auf False gesetzt. Die Änderung der Entität in Replica 2 bewirkt die Übernahme des LastSyncHash vom ursprünglichen CurrentHash. Dadurch kann beim nächsten Synchronisationsschritt (Replica 2 -> Replica 1) Konfliktlos entschieden werden, dass die Entität nur in Replica 2 geändert wurde und somit in Replica 1 überschrieben werden kann. Softwarearchitektur 32 Einfaches Synchronisations-Beispiel - Variante 2 Replica 1 Transport-Container Replica 2 Neue Entität A wird gespeichert A:ChangeTrackingEntity CH=1, LSH=null, LC=T A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=1, LSH=null, LC=F CH=1, LSH=null Replica 2 ist leer. A wird geändert A wird importiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=2, LSH=1, LC=T CH=1, LSH=null, LC=F A wird geändert A:ChangeTrackingEntity CH=3, LSH=1, LC=T A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=3, LSH=1, LC=F CH=3, LSH=1 A wird importiert A:ChangeTrackingEntity CH=3, LSH=1, LC=F Abbildung 7: Einfaches Synchronisations-Beispiel Variante 2 Softwarearchitektur 33 Das Beispiel in Abbildung 7 demonstriert eine mehrfache Synchronisation von einer Replica (hier Replica 1) ausgehend. Dieses Szenario ist im Bezug auf das Trainingstudio sehr interessant, da es in der Praxis häufig auftritt (Trainer -> Athleten). Wie auch im vorhergehenden Beispiel wird zu Beginn eine Entität (A) in Replica 1 erstellt. Beim Import in die Replica 2 wird wiederum festgestellt, dass keine analoge Entität existiert (-> Entität wird erstellt). Beim ersten Änderungsvorgang wird der LastSyncHash aktualisiert und das Flag LocallyChanged auf True gesetzt. Bei der nächsten Änderung bleibt der LastSyncHash aufgrund des LocallyChanged-Flags unverändert. Mit diesen Informationen kann beim weiteren Synchronisationsschritt (Replica 1 -> Replica 2) wieder ohne Konflikt importiert werden. Softwarearchitektur 34 Synchronisations-Beispiel mit Konflikten Replica 1 Transport-Container Replica 2 A:ChangeTrackingEntity A:ChangeTrackingEntity CH=2, LSH=1, LC=F CH=2, LSH=1, LC=F A wird geändert A wird geändert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=3, LSH=2, LC=T CH=4, LSH=2, LC=T A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=3, LSH=2, LC=F CH=3, LSH=2 A wird importiert Konfliktbehandlung: Replica 2 gewinnt A:ChangeTrackingEntity CH=4, LSH=2, LC=T A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=4, LSH=2 CH=4, LSH=2, LC=F A wird importiert Konfliktbehandlung: Replica 1 gewinnt A:ChangeTrackingEntity CH=3, LSH=2, LC=F Abbildung 8: Synchronisations-Beispiel mit Konflikten Softwarearchitektur Abbildung 8 35 zeigt ein klassisches Konflikt-Szenario, welches eine applikationsgesteuerte Konfliktbehandlung erfordert. In der Ausgangssituation existiert in beiden Replicas eine synchrone Entität, welche unabhängig verändert wird. Replica 1 möchte nun ihre Änderungen in Replica 2 importieren. Da allerdings der LastSyncHash der exportierten Entität nicht mit dem CurrentHash der Entität in Replica 2 übereinstimmt, entsteht ein Konflikt, welcher auf Applikationsebene aufgelöst werden muss. In diesem Beispiel wird davon ausgegangen, dass die Konfliktbehandlung zu Gunsten von Replica 2 entschieden hat. Dadurch bleibt die Entität in Replica 2 in ihrem Zustand unverändert. In dem darauf folgenden Synchronisationsschritt wird nun versucht die Entität aus Replica 2 mit der analogen Entität aus Replica 1 zu synchronisieren. Beim Importvorgang wird aufgrund der Unterschiede zwischen den Werten des LastSyncHash der exportierten Entität und dem CurrentHash der Entität in der ZielReplica erneut ein Konflikt erkannt. Softwarearchitektur 36 Synchronisations-Beispiel mit mehreren Teilnehmern Replica 1 Transport-Container Replica 2 Transport-Container Replica 3 A:ChangeTrackingEntity CH=1, LSH=null, LC=T A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=1, LSH=null, LC=F CH=1, LSH=null A wird geändert A:ChangeTrackingEntity A wird importiert A wird importiert Replica 2 ist leer. CH=2, LSH=1, LC=T Replica 3 ist leer. A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=2, LSH=1, LC=F CH=2, LSH=1 A:ChangeTrackingEntity A:ChangeTrackingEntity CH=1, LSH=null, LC=F CH=1, LSH=null, LC=F A wird importiert A:ChangeTrackingEntity CH=2, LSH=1, LC=F A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=2, LSH=1, LC=F CH=2, LSH=1 A wird importiert A:ChangeTrackingEntity CH=2, LSH=1, LC=F A wird exportiert A:ChangeTrackingEntity A:ChangeTrackingEntity CH=2, LSH=1 CH=2, LSH=1, LC=F A wird importiert A:ChangeTrackingEntity CH=2, LSH=1, LC=F Abbildung 9: Synchronisations-Beispiel mit mehreren Teilnehmern Softwarearchitektur 37 In Abbildung 9 wird ein komplexeres Synchronisations-Szenario mit drei Replicas dargestellt. Zu Beginn besitzt nur Replica 1 eine Entität, welche beim ersten Synchronisationsvorgang mit den beiden anderen Replicas abgeglichen wird. Im weiteren Verlauf erkennt man, dass der Algorithmus auch mit mehreren Parteien nach selben Schema durchgeführt werden kann. 15.3.2 Importreihenfolge Der folgende Algorithmus dient zum Berechnen einer Reihenfolge der unterschiedlichen Entitäts-Typen, welche ein problemloses Importieren ermöglichen soll. Da Entitäts-Typen Abhängigkeiten auf andere Entitäts-Typen besitzen können, sollte beim Importieren eine Reihenfolge angestrebt werden, sodass alle benötigten Entitäten bereits vorhanden sind. Es gibt dabei drei unterschiedliche Variationen. 1. Ein nicht hierarchischer Verweis auf einen anderen Entitäts-Typ. 2. Ein hierarchischer Verweis auf den Eltern Entitäts-Typ10. 3. Ein nicht hierarchischer rekursiver Verweis auf denselben Entitäts-Typ. Für die Variationen 1 und 2 existiert eine Reihenfolge – sofern keine Vererbungsoder Assoziationszyklen vorhanden sind – mit welcher die Entitäten problemlos importiert werden können. Da das Importieren einer Entität von IBOF durchgeführt wird, muss das Importieren einer hierarchischen Entität nur auf den wahren beziehungsweise höchst spezialisierten Typ angewandt werden. Deshalb sollten zuerst die in der Vererbungshierarchie höchst spezialisierten Typen importiert werden, da ansonsten eine Entität mehrfach importiert wird. Die Arbeitsweise des Algorithmus sieht folgendermaßen aus: 1. Zuerst werden alle Entitäts-Typen anhand ihrer Position in der Vererbungshierarchie gruppiert, sodass die Entitäten in den unterschiedlichen Gruppen keine hierarchischen Abhängigkeiten mit Entitäten in anderen Gruppen besitzen. 10 IBOF ermöglicht ein objektorientiertes Vererbungskonzept ohne Mehrfachvererbung, wodurch nur ein Eltern-Knoten zu einem Kind-Knoten existiert. Softwarearchitektur 38 2. Nun wird eine beliebige Gruppe gewählt und alle Entitäts-Typen durchlaufen. Die Reihenfolge der Entitäts-Typen sollte dabei vom hierarchischen Spezialisierungsgrad absteigend geordnet sein. Dadurch sind die Entitäts-Typen, die zur selben Gruppe gehören, untereinander bereits richtig geordnet. 3. Falls der Entitäts-Typ bereits behandelt wurde wird er nun ignoriert um endlose rekursive Aufrufe zu vermeiden. 4. Falls der Entitäts-Typ Verweise auf Entitäts-Typen außerhalb der Gruppe besitzt (Forward-Links), dann werden die Sortiermaßnahmen (ab Schritt 2) rekursiv auf die Hierarchie-Gruppen der referenzierten Typen angewandt. Der aktuelle Entitäts-Typ wird nach den Entitäts-Typen eingereiht, die rekursiv behandelt wurden. 5. Falls andere Entitäts-Typen Verweise auf den aktuellen Entitäts-Typ besitzen (Backward-Links), dann werden die Sortiermaßnahmen (ab Schritt 2) rekursiv auf diese Entitäts-Typen angewandt. Der aktuelle Entitäts-Typ wird vor den Entitäts-Typen eingereiht, die rekursiv behandelt wurden. 6. Wenn alle Entitäts-Typen der Gruppe behandelt wurden, dann liegen die Hierarchie-Gruppen, die mit der gewählten Hierarchie-Gruppe zusammenhängen, in einer absoluten Ordnung vor. Falls noch HierarchieGruppen existieren, welche mit den bereits behandelten Gruppen strukturell nicht zusammenhängend sind, dann wird der Schritt 2 solange mit den neuen Gruppen wiederholt, bis alle Gruppen behandelt wurden und eine Ordnung für alle Gruppen existiert. Folgender Pseudo-Code zeigt eine Beispielimplementierung für den beschriebenen Algorithmus. PROCEDURE Main ARGUMENTS groupLst : A list of grouped entity types BEGIN FOR group groupLst CALL OrderGroups(group) ENDFOR END PROCEDURE OrderGroups ARGUMENTS group : A group of entity types in the same hierarchy Softwarearchitektur 39 BEGIN IF group is not marked THEN MARK group FOR forwardLink group.forwardLinkLst CALL OrderGroups(forwardLink) ENDFOR FOR entityType group ordered by specialization level descending INSERT entityType at the end of orderedGroupsLst ENDFOR FOR backwardLink group.backwardLinkLst CALL OrderGroups(backwardLink) ENDFOR ENDIF END Die Prozedur Main bekommt bereits die Liste von gruppierten Entitäts-Typen (groupLst) übergeben. Die einzelnen Gruppen dieser Liste können markiert werden, sodass überprüft werden kann, ob die Gruppen bereits behandelt wurden. Dies geschieht mit dem Befehl MARK. In die Liste orderedGroupsLst werden die Entitäts-Typen geordnet eingefügt. Die Liste ist dabei global zugänglich, damit alle rekursiven Methoden-Aufrufe auf die Liste zugreifen können. Falls die Entitäts-Typen Zyklen oder Abhängigkeiten mit Variation 3 enthalten, so kann der Algorithmus keine problemfreie Ordnung finden. Da der Algorithmus die bereits behandelten Entitäts-Typen nicht mehr weiterverfolgt terminiert der Algorithmus. Um die Entitäten später auch unter diesen Bedingungen zu importieren, müssen vor dem Import-Vorgang die Entitäten manipuliert werden (siehe 17.4.4). 16 16.1 Logische Sicht Komponentenarchitektur ThemiSync wird in vier Packages beziehungsweise VisualStudio Projekte unterteilt um den Quellcode noch zusätzlich zu strukturieren. Die vier Packages BusinessObjects, Synchronization, Exception und Utils werden in Abbildung 10 dargestellt und in folgenden Abschnitten besprochen. Softwarearchitektur 40 ThemiSync BusinessObjects Synchronization Exceptions Utils Abbildung 10: Komponentenarchitektur Überblick 16.1.1 ThemiSync ThemiSync ist das Basispackage der API. Es dient als Einstiegspunkt zur Synchronisation und delegiert Methodenaufrufe an die entsprechenden Stellen weiter. Die wichtigsten Klassen dieser DLL sind in Abbildung 11 zu sehen: Softwarearchitektur 41 Abbildung 11: Package ThemiSync Übersicht ThemiSyncConfig Diese statische Klasse bietet diverse globale Einstellmöglichkeiten für laufzeitbedingte Charakteristiken. Eine elementare Methode zum Initialisieren aller DAC-Klassen11 stellt InitializeEntityTypes() dar. Dies wird benötigt damit ThemiSync an den entsprechenden Stellen über Speichervorgänge der BusinessObjects informiert wird und ThemiSync-eigene Metadaten aktualisieren kann. Durch dieses flexible Konzept ist es möglich, ohne Eingriff in die bestehende Applikation und deren Geschäftsmodell ThemiSync zu integrieren. ThemiSyncExport Die Klasse ThemiSyncExport ermöglicht es unter Angabe eines Exportpfades und der Quelldatenbank die synchronisationsrelevanten Daten (definiert durch Konfigurationen, siehe 17.3) in einen Transportcontainer zu Exportieren. 11 DAC-Klassen (Data Access Class) sind hier von IBOF generierte Klassen, welche einen einfachen Zugriff auf persistierte Datenobjekte ermöglichen. Zusätzlich bieten diese Klassen auch Metainformationen über die korrelierenden Objekttypen welche von ThemiSync verwendet werden. Softwarearchitektur 42 ThemiSyncImport ThemiSyncImport obliegt das Importieren aller Daten eines Transportcontainers. Dafür wird sowohl der Pfad zur Containerdatei als auch die Zieldatenbank benötigt. Weiters wird über diese Klasse das gesamte Konflikthandling, welches während des Importvorganges auftreten kann, gesteuert. Falls ThemiSync während des Importvorgangs einen Konflikt nicht automatisiert auflösen kann, weil beispielsweise zwei abzugleichende Entitäten jeweils unabhängig ihren Zustand geändert haben, wird der benutzerdefinierte Handler aufgerufen, sofern einer registriert wurde und in den Einstellungen aktiviert wurde. Zusätzlich besteht auch die Möglichkeit bei komplexen Geschäftsmodellen einen benutzerdefinierten Speichervorgang zu verwenden. 16.1.2 BusinessObjects Dieses Package enthält die gesamte Businesslogik von ThemiSync, welche zum Organisieren der erforderlichen Metadaten und zur Systemkonfiguration benötigt wird. Außerdem sind Klassen zur Protokollierung von Datenstandänderungen, so genannte ChangeTracking-Entities beziehungsweise Tombstone-Entities enthalten. Die Grundstruktur dieser Bibliothek wurde von IBOF generiert und ist somit Voraussetzung einer ThemiSync erweiterten Applikation. Softwarearchitektur 43 Abbildung 12: Datenmodell Grundstruktur Abbildung 12 veranschaulicht die von IBOF generierten „Entity“-Klassen, welche von IBOF aus deren entsprechenden Tabellen generiert wurden. EntityTypeEntity Die Klasse EntityTypeEntity bildet die synchronisierbaren Entitäts-Typen ab. Neben der genauen Identifikation der Typen wird noch zusätzlich eine totale Ordnung bereitgestellt um Abhängigkeiten während den Synchronisationsvorgängen einfacher aufzulösen. ChangeTrackingEntity Zu jeder synchronisierbaren Entität existiert genau eine ChangeTrackingEntity Entität, welche Metadaten, die für die Synchronisationsvorgänge benötigt werden, enthalten. Dabei wird unter anderem der Objekt-Zustand der Entität, anhand eines Softwarearchitektur 44 Hashcodes gespeichert. Falls eine Entität gelöscht wird, dann wird auch deren ChangeTrackingEntity Entität gelöscht. TombstoneEntity Wenn eine synchronisierbare Entität gelöscht wird, dann wird eine TombstoneEntity Entität erstellt um diesen Löschvorgang zu protokollieren und gegebenenfalls auch auf andere Replicas anzuwenden. ConfigurationEntity Um Synchronisationsvorgänge vorzubereiten werden ConfigurationEntity Entitäten benötigt, welche entweder ImportConfigurationEntity Entitäten oder ExportConfigurationEntity Entitäten darstellen. Dabei werden auch Einstellungen für die Synchronisationsvorgänge festgelegt. Die Klasse ImportRuleEntity legt fest, wie ThemiSync bei einem Synchronisations-Konflikt reagieren soll und PreImportActionEntity ermöglicht Aktionen, wie das Leeren von Tabellen vor dem Importieren durchführen zu können. Jede sogenannte Configuration betrifft allerdings genau eine EntityTypeEntity Entität, also genau einen synchronisierbaren Typ. Ohne Configuration Entitäten einer EntityTypeEntity Entität ist es nicht möglich diesen Typ zu synchronisieren. ConfigurationGroupEntity Die Klasse ConfigurationGroupEntity wird dafür benötigt einen atomaren Synchronisationsvorgang anhand mehrerer Configuration Entitäten durchzuführen. ConfigurationGroupMappingEntity Mit dieser Klasse können Verknüpfungen zwischen ConfigurationGroupEntity Entitäten hergestellt werden, welche zum Erleichtern des Import-Vorgangs dienen. Dadurch kann festgellegt werden welche ConfigurationGroupEntity Entity beim Import-Vorgang automatisch angewandt wird, beim Importieren einer bestimmten ConfigurationGroupEntity Entity. SystemInfoEntity Entitäten dieser Klasse beschreiben globale Informationen und Einstellungen der ThemiSync-Instanz. Softwarearchitektur 45 In folgender Abbildung 13 werden weitere wichtige Klassen illustriert, die sich im Package BusinessObjects befinden. Abbildung 13: Diverse Klassen EntityManager Die Klasse EntityManager stellt allgemeine Operationen bereit, die auf synchronisierbare Entitäten angewendet werden können. Zum Beispiel das Kopieren von Entitäten auf andere Replicas, oder aber auch das aktualisieren der ChangeTrackingEntity Entitäten einer synchronisierbaren Entität ermöglicht diese Klasse. DacDependencyGraph Diese Klasse ermöglicht die Abhängigkeiten der synchronisierbaren Entitäten zu analysieren und mit einem Algorithmus (siehe 15.3.2) eine möglichst konfliktfreie Import-Reihenfolge zu berechnen. 16.1.3 Synchronization Hier findet man alle Klassen, welche für die eigentlichen Synchronisationsprozesse und für das Handling des Transportcontainers zuständig sind. Der Großteil der Funktionalität wird aus dem ThemiSync Package hier her delegiert. Die bedeutendsten Klassen in dieser Bibliothek sind folgend kurz beschrieben und in Abbildung 14 illustriert: Softwarearchitektur 46 Abbildung 14: Datenmodell Synchronization Import- und Exportaction Instanzen dieser Klassen führen jeweils einen atomaren Synchronisationsprozess durch. Importhandler Der Importhandler ermöglicht den Programmfluss zu bestimmten Zeitpunkten beziehungsweise an definierten Stellen zu beeinflussen, wodurch komplexe Geschäftsmodelle auch dann gespeichert werden können, wenn eine Gefahr auf Datenbank-Constraint-Konflikte besteht. Als Beispiel sei hier eine zyklische Abhängigkeit zwischen den Business Objects, welche in der Datenbank mittels Fremdschlüssel abgebildet wurden. DBArchive Das DBArchive stellt im Grunde eine Virtualisierung eines Datencontainers dar und ist für das Speichern und Laden von Transportdatenbanken zuständig. Die konkrete Technologie zum Abbilden dieser Datenbanken in ein Dateisystem kann generisch über den Einsatz einfacher Wrapperklassen definiert werden. Die aktuelle ThemiSync Implementierung enthält bereits einen Wrapper für das DBMS Microsoft SQL Server Compact. Softwarearchitektur 16.2 47 Querschnittskomponente Folgende Komponenten sind fachlich keinem Paket eindeutig zuordenbar und werden von diversen anderen Komponenten referenziert: 16.2.1 Utils Die Klassen dieser Bibliothek enthalten diverse Hilfsfunktionen, welche an mehreren Stellen Verwendung finden. Vor allem die Third-Party Bibliotheken werden über Klassen in diesem Package angesprochen. Folgende Abbildung 15 gibt einen kurzen Überblick über die Klassen aus dem Package Utils. Abbildung 15: Datenmodell Utils 16.2.2 Exceptions Um sowohl eine Exception-Hierarchie, ausgehend von ThemiSyncException zu gewährleisten, als auch zirkuläre Abhängigkeiten zwischen den Packages zu vermeiden, wurden alle Exceptions in ein separates Package ausgelagert. Abbildung 16 illustriert die Exception und deren Abhängigkeiten untereinander. Softwarearchitektur 48 Abbildung 16: Datenmodell Exceptions 16.3 Anwendungskern Zur Steuerung der Import- und Exportvorgänge bildet ThemiSync die Konfigurationseinstellungen in der Datenbank mit den Klassen ImportConfiguration und ExportConfiguration ab. Wichtig ist hierbei, dass jede Konfiguration sich eindeutig auf einen Typ der Applikations-Anwendungslogik bezieht. Für jeden Typ können beliebig viele Konfigurationsinstanzen existieren. Dieses Konzept erlaubt es Vorlagen für Synchronisationsprozesse einzusetzen und ist in folgende Klassenhierarchie aufgebaut: Softwarearchitektur 49 Abbildung 17: Configuration Klassenhierarchie - vereinfachte Darstellung Wie in Abbildung 17 ersichtlich, besteht eine ConfigurationEntity neben einer Beschreibung aus folgenden Attributen: SqlWhereStatement /SqlJoinStatement Um zu definieren welche Daten exportiert beziehungsweise importiert werden sollen, bedient sich ThemiSync einer benutzerdefinierten Datenbankabfrage. Diese setzt sich aus dem SqlWhereStatement und dem SqlJoinStatement zusammen. UseTombstoneEntities Dieses Flag entscheidet, ob gelöschte Datensätze des referenzierten Datentyps exportiert beziehungsweise importiert werden. Wenn gelöschte Datensätze exportiert und bei einer anderen Replica wieder importiert werden, dann werden die betreffenden Datensätze falls kein Konflikt auftritt gelöscht. Dieses Flag dient als Schutzmechanismus sowohl für den Export als auch für den Import. Der Synchronisierungsprozess kann in zwei große Bereiche, Export und Import unterteilt werden. Für diese Bereiche gibt es jeweils spezialisierte Konfigurationsklassen, wobei nur die Importkonfiguration zusätzliche Attribute benötigt. Zum einen gibt es das Attribut PreImportAction welches bestimmte Softwarearchitektur 50 Operationen vor dem Import auf die entsprechende Tabelle ausführt (z.B. löschen des gesamten Tabelleninhaltes) und zum Anderen wird im Attribut ImportRule die Regel angegeben, welche ausgeführt wird, wenn ein Import-Konflikt auftritt. Dabei besteht die Möglichkeit anzugeben, ob der neue oder der alte Datensatz schlussendlich in der Datenbank gespeichert wird beziehungsweise erhalten bleibt. Falls eine benutzerdefinierte Behandlung erforderlich ist, muss diese in der ImportRule aktiviert werden, sodass die registrierten Methoden aufgerufen werden. Einzelne Konfigurationsinstanzen werden zu so genannten Konfigurationsgruppen (ConfigurationGroupEntity) zusammengefasst und stellen als solche eine atomare Synchronisationseinheit dar. Die Gruppen sind durch einen eindeutigen Namen definiert, welcher in den Exportdaten mitgespeichert wird. Damit ist es möglich, beim Import automatisch die zugehörige Import-Konfigurationsgruppe auszuwählen. Dies wird durch die Klasse ConfigurationGroupMappingEntity ermöglicht, welche wie in folgender Abbildung 18 dargestellt in das System eingefügt ist. Softwarearchitektur 51 Abbildung 18: Konfigurationsgruppen - vereinfachte Darstellung 16.3.1 Export Der Exportvorgang besteht banalisiert ausgedrückt aus der Selektion für die Synchronisation relevanten Daten und dem Erstellen eines Transport-Containers, welcher mit den selektierten Daten befüllt wird. Um den Exportvorgang anzustoßen, muss eine Instanz der Klasse ThemiSyncExport erstellt werden, wofür sowohl ein Datenbankobjekt12 der Quelldatenbank (Standardmäßig wird die IBOF Default-Database verwendet), als auch der Pfad des resultierenden Transportcontainers benötigt wird. Der bestehenden Instanz kann nun eine Liste von ConfigurationGroupEntities übergeben werden, welche beim Ausführen der Methode Start() abgearbeitet wird. Dabei wird für jeden Listeneintrag 12 Hierbei ist ein Objekt vom Typ InfPro.Datenbank.Database gemeint. Softwarearchitektur 52 eine ExportAction erstellt, welche einen atomaren Exportvorgang durchführt. Nachdem alle Exportvorgänge durchgeführt wurden, werden die resultierenden Datenbankfiles in einen Transportcontainer verpackt und im Dateisystem abgespeichert (ExportPath). Folgende Grafik (Abbildung 19) zeigt den schematischen Ablauf eines Exportvorganges. Datenbankfile Für jede Konfiguration wird ein erstellt (Access, SQL CE, …). Diese Files werden zu einem Von IBOF unterstütztes DB-System Transportcontainer zusammengefasst. Datenbank Alle Daten Gefilterte Daten Transportcontainer ThemiSync-Erweiterte IBOF Applikation. Instanz von ThemiSyncExport wird mit beliebig vielen ConfigurationGroupEntity-Entitäten initialisiert. Abbildung 19: Ablauf Exportvorgang 16.3.2 Import Der Importvorgang besteht, ähnlich dem Exportvorgang, aus einer Selektion der im Transport-Container enthaltenen Daten, welche je nach Import-Konfiguration mit ihren analogen Datensätzen der Zieldatenbank verglichen beziehungsweise behandelt werden. Um einen Importvorgang zu beginnen, wird eine Instanz der Klasse ThemiSyncImport angelegt, wofür zwingend der Pfad zum Transport-Container benötigt wird. Sollte für den Import nicht die IBOF Standarddatenbank verwendet werden, kann die gewünschte Zieldatenbank zusätzlich spezifiziert werden. Mit dem Aufruf der Methode Start() wird der gesamte Inhalt des TransportContainers analysiert und für jede der darin enthaltenen Datenbanken eine Instanz der Klasse ImportAction erstellt. Diese stellen analog zur ExportAction einen atomaren Importvorgang dar. Während des Importvorganges wird anhand der Importkonfigurationen und der Metadaten sowohl von der Quell-, als auch von der Zieldatenbank, eine Selektion der importfähigen Datensätze durchgeführt. Softwarearchitektur 53 Falls für einen Datensatz nicht automatisch entschieden werden kann, ob er importiert werden soll oder nicht, wird ein Konfliktereignis ausgelöst, welches die optional registrierten Ereignishandler informiert. Damit haben die Ereignishandler die Möglichkeit benutzerdefiniert über den weiteren Synchronisationsverlauf zu entschieden. Eine besondere Schwierigkeit beim Importvorgang stellen komplexe Strukturen im Datenmodell dar. So bildet IBOF Beziehungen im Geschäftsmodell anhand von Fremdschlüsseln in der Datenbank ab. Da das temporäre Deaktivieren der Fremdschlüssel, was ein möglicher Lösungsansatz wäre, den Speichervorgang in seiner Performance stark beeinträchtigt, verwendet ThemiSync diverse Routinen zum Vermeiden von Konflikten im Zusammenhang mit Fremdschlüssel. Für sehr viele Standardfälle implementiert ThemiSync einen Algorithmus zum automatischen Bestimmen der Speicherreihenfolge (siehe 15.3.2). Zusätzlich gibt es die Möglichkeit diese Reihenfolge benutzerdefiniert vorzugeben. Für zyklische Abhängigkeiten im Datenmodell genügt es nicht die Reihenfolge auf Tabellenebene zu bestimmen, da derartige Strukturen aufgrund wechselseitiger Referenzierenden nicht mit einer einfachen Operation in der Datenbank persistiert werden können. Zur Auflösung dieser Abhängigkeiten sind mehrere Lösungsansätze denkbar. Um möglichst generisch und flexibel zu bleiben, bietet ThemiSync über PreImportEvents beziehungsweise PostImportEvents die Möglichkeit, Abhängigkeiten vor dem Importieren aufzulösen beziehungsweise nach dem Importieren wiederherzustellen. Folgende Grafiken präsentieren Beispiele, welche die genannte Problematik verdeutlichen sollen und die Entscheidung für den gewählten Lösungsansatz begründen: Softwarearchitektur 54 Abbildung 20: Objekthierarchie Das dargestellte Beispiel in Abbildung 20 zeigt eine Hierarchie welche problemlos durch Beachten der Speicherreihenfolge der einzelnen Datensätze gelöst werden kann. Eine mögliche Reihenfolge wäre zum Beispiel: D, C, B, A In Fällen von Assoziationszyklen oder Rekursionen wäre ein Lösungsansatz, welcher sich rein auf die Änderung der Speicherreihenfolge beschränkt nicht ausreichend. Mit dem PreImport- beziehungsweise PostImportEvents sind auch derartige Fälle abzubilden, da man während eines PreImportEvents die Referenzen aushebeln kann und diese nach dem Speichern während des PostImportEvents wieder einfügen kann. 17 Implementierungssicht In diesem Abschnitt werden die wichtigsten Komponenten der ThemiSync API aus implementierungstechnischer Sicht beleuchtet. 17.1 Initialisierung Um ThemiSync verwenden zu können, müssen beim Applikationsstart alle synchronisierbaren DAC-Klassen der Methode Initialize() der Klasse ThemiSyncConfig übergeben werden. Hierbei wird empfohlen, dass die DACKlassen mit dem Methodenaufruf DatabaseManager.Instance.GetAllRegisteredDACClasses() ermittelt werden. Softwarearchitektur 55 Die Initialize-Methode überprüft das IBOF-Flag IsUsedForSynchronization und registriert einen Eventhandler für das Ereignis BeforeSave, falls dieses auf True gesetzt ist. Dadurch werden nur Klassen, welche für die Synchronisierung vorgesehen sind überwacht. Die übergebenen DAC-Klassen werden für die weitere Verwendung zwischengespeichert. Bei erstmaliger Initialisierung wird die Tabelle EntityType aufgebaut und die Abhängigkeiten in der Business-Logik automatisch aufgelöst, indem die Speicherreihenfolge der Entitäts-Typen berechnet wird. Um die Berechnungen später erneut durchzuführen – wegen eventuell geänderten beziehungsweise erweiterten Tabellenstrukturen – muss das Flag CleanEntityTypes in der Tabelle SystemInfo den Wert True erhalten. Nach erneutem Initialisieren der DAC-Klassen, wird das Flag wieder zurück auf False gesetzt. Softwarearchitektur 56 Klassen, die in diesem Implementierungs-Abschnitt eine Rolle spielen werden in folgender Abbildung 21 in Form eines Klassendiagramms dargestellt: Abbildung 21: Klassendiagramm Initialisierung Softwarearchitektur 17.1.1 57 Ablauf Folgendes Sequenzdiagramm in Abbildung 22 visualisiert einen vollständigen Initialisierungsablauf, welcher konfigurationsabhängig beim Start einer ThemiSyncerweiterten IBOF-Applikation ausgeführt wird. Program :ThemiSyncConfig :DacDependencyGraph :EntityTypeDAC Initialize(db, dacs) InitializeEntityTypes(db, dacs) updateResolutionSequence(db, dacs) ResolveDependencyOrder(dacs) orderedDacs createAllChangeTrackingData(db, dacs) Abbildung 22: Sequenzdiagramm zum Visualisieren eines vollständigen Initialisierungsvorgangs Beim Start einer ThemiSync-erweiterten IBOF-Applikation müssen die DACKlassen aller synchronisierbaren Entitäten als Liste der Methode public static void Initialize (Database database, List<IBusinessObjectDAC> iBusinessObjectDACLst) übergeben werden. Diese Methode überprüft die Kompatibilität der übergebenen Klassen zu ThemiSync. Hierbei wird überprüft, ob ein Primärschlüssel existiert, dieser aus genau einem Attribut besteht und den C#-Datentyp Guid besitzt. Falls eine der Klassen die genannten Kriterien nicht erfüllt, wird eine ConfigurationException geworfen. Anderenfalls werden die Klassen über die EntityTypeDAC SingletonInstanz verarbeitet. Softwarearchitektur 58 Die Methode public void InitializeEntityTypes(Database database, List<IBusinessObjectDAC> iBusinessObjectDACs) erstellt zu jedem Eintrag der Liste iBusinessObjectDACs eine entsprechende EntityType Entität und macht diese über einen Cache applikationsweit zugänglich. Hierbei werden die von IBOF bereitgestellten Informationen (Namespace, Klassenname) über die zugehörige DAC-Klasse verwendet. Die Klasse EntityTypeEntity besitzt folgende Attribute, welche zum eindeutigen Zuordnen der synchronisierbaren Entitäten zu deren entsprechenden Datentypen bestimmt sind: EntityTypeID Primärschlüssel vom C# Datentyp short. Dieser Datentyp wurde gewählt, da die unterschiedlichen Datentypen beziehungsweise Klassen in Geschäftsmodellen dadurch effizient abbildbar sind. EntityName Bezeichnet den Klassenname des abgebildeten Datentyps. EntityNamespace Bezeichnet den C# Namespace. ResolutionSequenceNumber Speichert die Abarbeitungsreihenfolge für Synchronisationsvorgänge. Folgende Auflistung beschreibt weitere Attribute und Methoden der Klasse EntityTypeDAC: createNewEntityType Private Methode, welche aus den übergebenen Parametern eine EntityType Entität in der spezifizierten Datenbank erstellt und zurück gibt. GetEntityType Öffentliche Methode, welche den passenden EntityType Objekt zum übergebenen C#Datentyp zurück beachten, dass gibt. nur Hierbei EntityType ist zu Objekte zurückgegeben werden, welche aus der Softwarearchitektur 59 Standard-Datenbank stammen. GetTypeToEntityType Öffentliche übergebenen Methode, welche EntityType aus Entität der den dazugehörigen Datentyp zurück gibt. Hierbei ist zu beachten, dass nur Datentypen zu EntityType Entitäten der Standard-Datenbank zur Verfügung stehen. GetTypeToEntityTypeID Diese öffentliche Methode verhält sich analog zur Methode GetTypeToEntityType. Allerdings wird hier der primitive Datentyp short übergeben, Probleme wodurch mit eventuelle unterschiedlichen Datenbanken13 vermieden werden können. FindByEntityNameAndNameSpace Öffentliche Methode, welche die bereits von IBOF angebotenen Find-Methoden erweitert, sodass bequem nach EntityType Entitäten mittels Klassenname und Klassen- Namespace gesucht werden kann. Durch diese beiden Parameter sind alle EntityType Entitäten eindeutig spezifiziert. FindByAbstractBusinessObject Öffentliche Methode, welche die zugehörige EntityType Entität zu dem übergebenen AbstractBusinessObject zurück gibt. Aufgrund der Abhängigkeiten der BusinessObjects ist eine bestimmte Sequenz beim Persistieren nötig. Diese wird nach dem Erstellen aller EntityType Entitäten automatisiert von der Methode 13 Problem mit unterschiedlichen Datebanken können auftreten falls mehrere EntityType Entitäten aus verschiedenen Datenbanken stammen, und daher im Cache nicht mehr eindeutig zugeordnet werden können. Softwarearchitektur 60 private void updateResolutionSequence(Database database, List<IBusinessObjectDAC> dacs) aktualisiert. Die eigentliche Berechnung einer korrekten Sequenz erfolgt in der Klasse DacDependencyGraph. Nachdem die EntityType Entitäten erstellt, und deren Abhängigkeiten aufgelöst wurden, werden die ChangeTracking Entitäten in folgender Methode erstellt: private void updateResolutionSequence(Database database, List<IBusinessObjectDAC> dacs) Sowohl die Auflösung der Abhängigkeiten, als auch das Erstellen der fehlenden ChangeTracking Entitäten werden im Falle von bereits bestehenden EntityType Entitäten inkrementell auf DAC-Klassen, welche nach der Erst-Initialisierung als synchronisierbar markiert wurden, ausgeführt. Eine vollständige Neu-Initialisierung der EntityType Entitäten, welche beim Deaktivieren von synchronisierbaren BusinessObjects die Datenbank bereinigt, wird über eine Entität des Typs SystemInfoEntity angestoßen (Siehe 27.5). Um in der ThemiSync-API auf Änderungs- beziehungsweise Speichervorgänge in der Business-Logik reagieren zu können, ohne Änderungen am Quellcode von ThemiSync-erweiterten IBOF-Applikationen vornehmen zu müssen, bedient sich ThemiSync dem Event-Konzept von C#. Aus diesem Grund wird abschließend die Methode public static void UpdateMetaData(object sender, AbstractBusinessObjectsEventArgs e) der Klasse EntityManager für die Speicher-Events BeforeSave, welche in den von IBOF bereitgestellten DAC-Klassen angeboten werden. 17.2 Metadaten Die Implementierung des Synchronisationsalgorithmus von ThemiSync (beschrieben in 15.3.1) verwendet sogenannte Metadaten, auf deren Erstellung und Verwaltung in den folgenden Abschnitten eingegangen wird. Softwarearchitektur 17.2.1 61 Metadaten Struktur Abbildung 23: Datenmodell Metadaten-spezifische Klassen Eine Übersicht über die Klassen, welchen Metadaten-spezifische Bedeutungen zukommen, bietet Abbildung 23. Die ThemiSync-API benötigt verschiedene Metadaten um den verwendeten Synchronisationsalgorithmus (siehe 15.3.1) durchführen zu können. Diese Softwarearchitektur 62 Informationen werden in Tabellen eines ThemiSync-spezifischen Datenbankschemas gespeichert, um möglichst wenige Anpassungen auf bereits bestehende Anwendungen und deren Geschäftsmodell nötig zu machen. Änderungen an synchronisierbaren Entitäten werden mit ChangeTrackingEntity Entitäten erfasst. Zu jeder synchronisierbaren Entität existiert genau eine ChangeTrackingEntity Entität, welche den aktuellen Objektzustand anhand eines Hashcodes im Attribut EntityHash abbildet. Der Hashcode des letzten synchronen Objektzustandes wird im Attribut LastSyncHash gespeichert. Diese beiden Attribute erlauben dem Synchronisationsalgorithmus die direkte Entscheidung, ob die Entität importiert werden kann, oder ob ein Konflikt-Ereignis auftritt. Das boolesche Attribut LocallyChanged zeigt an, ob sich die Entität seit der letzten Synchronisation geändert hat. Es wird bei der jeweils ersten Änderung nach einem Synchronisationsprozess auf True gesetzt und verhindert damit das erneute Überschreiben des LastSyncHashs bei weiteren Änderungen. Damit in einer zentralen Tabelle alle Entitäten tabellenübergreifend abgebildet werden können, werden die folgenden zwei Attribute benötigt: EntityID Speichert die eindeutige ID14 der referenzierten Entität. EntityTypeID Beschreibt die Entitätsklasse mittels Verweis auf die entsprechende EntityType Entität. Werden synchronisierbare Entitäten gelöscht, so muss ThemiSync dies mitprotokollieren, um bei der Synchronisation entsprechend darauf reagieren zu können. Diese Informationen werden in TombstoneEntity Entitäten gespeichert. Hierbei wird analog zur ChangeTrackingEntity die gelöschte Entität mittels EntityID und EntityTypeID eindeutig identifiziert. 14 Im Rahmen des Projektes kann davon ausgegangen werden, dass jeder Datensatz mit einem Primärschlüssel des C# Datentyps Guid (Global Unique Identifier) Replica-weit eindeutig ist. Softwarearchitektur 17.2.2 63 Aktualisierung der Metadaten Die Aktualisierung der Metadaten erfolgt bei jedem Speichervorgang einer synchronisierbaren Entität. Mit der Registrierung des Ereignisses OnBeforeSave während der Initialisierung von ThemiSync wird unmittelbar vor dem Speichern der Entität in der Datenbank die statische Methode public static void UpdateMetaData(object sender, AbstractBusinessObjectsEventArgs e) der Klasse EntityManager ausgeführt. Beim Speichervorgang jedes AbstractBusinessObjects15 wird von IBOF entschieden, ob die Entität in der Datenbank erstellt, geändert oder gelöscht werden soll. Für die Methode UpdateMetaData ist in erster Linie interessant, ob die Entität gelöscht werden soll oder in der Datenbank erhalten bleibt. Falls die Entität nicht gelöscht wird, dann wird die zugehörige ChangeTrackingEntity Entität aktualisiert oder neu erstellt, sofern diese noch nicht existiert. Liegt eine Änderung vor, dann wird anhand des LocallyChanged-Flags überprüft, ob es die erste Änderungen nach dem letzten Synchronisationsvorgang ist. Ist dies der Fall, so wird der LastSyncHash mit dem CurrentHash vor der Änderung überschrieben. In jedem Fall wird der CurrentHash abschließend an den aktuellen Objektzustand angepasst. Wird die Entität allerdings gelöscht, so ist eine bereits bestehende, zugehörige ChangeTrackingEntity Entität ebenfalls aus der Datenbank entfernt. Um den Löschvorgang zu protokollieren wird eine TombstoneEntity Entität erstellt und in der Datenbank persistiert. Es kann vorkommen, dass eine Entität gelöscht wird und zu einem späteren Zeitpunkt wieder importiert wird. Wenn diese Entität erneut gelöscht wird, dann wird keine zusätzliche TombstoneEntity Entität erzeugt. 15 AbstractBusinessObject ist der Basisdatentyp aller von IBOF generierten, persistierbaren Entitäten. Softwarearchitektur 17.2.3 64 Hashcode-Berechnung Um den aktuellen Objektzustand einer synchronisierbaren Entität effizient und platzsparend abzubilden, wird über alle persistierbaren Properties ein eindeutiger Hashcode erstellt. In der aktuellen Implementierung wird dafür der Algorithmus MD516 verwendet. Um die Daten für die Hashcode-Generierung aufzubereiten, wurde eine eigene Methode für die Serialisierung entwickelt. Obwohl eine entsprechende Methode von C# bereits nativ angeboten wird, wurde die statische Methode public static byte[] Serialize(AbstractBusinessObject obj) der Klasse IbofHashFormatter selbst implementiert. Dies wurde aus Effizienzgründen gemacht, da von IBOF entsprechende Metadaten zur Verfügung stehen, um die Serialisierung ohne aufwendige Reflections (siehe 13) durchzuführen. Außerdem konnte dadurch die Serialisierung exakt auf die Bedürfnisse der synchronisierbaren Entitäten angepasst werden. Serialize() verwendet von IBOF angebotene Metadaten um alle Entitäts-relevanten Werte in einem Byte-Array abzubilden. Die endgültige Verarbeitung des Byte-Arrays zum Hashcode erfolgt in der statischen Methode public static Guid GenerateHashCode(AbstractBusinessObject businessObject) der Klasse IbofHashGenerator. Der berechnete Hashcode wird in Form des Typs Guid zurückgegeben, da dies ein primitiver C# Datentyp ist, und somit effizient weiterverarbeitet werden kann. 17.2.4 Beschreibung weiterer Klassen Weitere Metadaten-bezogene Methoden und Klassen werden folgend tabellarisch aufgelistet und beschrieben. Die Auflistung enthält nur relevante Inhalte und ist nicht vollständig. 16 Message-Digest Algorithm Softwarearchitektur 65 EntityManager public static void SaveToSpecifiedDatabase( AbstractBusinessObject, Diese Methode erlaubt das einfach Kopieren eines AbstractBusinessObjects in eine Database, spezifizierte Datenbank (Parameter vom Typ IBusinessObjectDAC) InfPro.Datenbank.Database). Diese Methode wird sowohl beim Exportieren als auch beim Importieren verwendet. public static void Update( AbstractBusinessObject, ChangeTrackingEntity, Diese Methode ersetzt eine Entität und die dazugehörige ChangeTrackingEntity-Entität AbstractBusinessObject, (ersten zwei Parameter) mit einer neuen Entität ChangeTrackingEntity) beziehungsweise ChangeTrackingEntity-Entität (letzen zwei Parameter). Diese Methode findet bei Importkonflikten ihren Einsatz falls die bestehende Entität überschrieben werden soll. public static ChangeTrackingEntity CreateMetadata( Database, Erstellt die erforderlichen Metadaten für eine Entität (AbstractBusinessObject) in der übergebenen Datenbank (Database). AbstractBusinessObject) ChangeTrackingDAC Public ChangeTrackingEntity FindByAbstractBusinessObject( Database, AbstractBusinessObject) Diese Methode findet die passende ChangeTrackingEntity-Entität zur übergebenen AbstractBusinessObject-Entität. Wird kein passender Eintrag gefunden, so gibt sie null zurück. Bei mehrfacher Existenz wird eine CorruptMetadataException geworfen. Public ChangeTrackingEntity FindByEntityIDAndTypeUnique( Databas,Guid, short) Findet die passende ChangeTrackingEntity- Entität in einer Datenbank (Database) anhand ihrer eindeutigen ID (Guid) und der EntityType- Softwarearchitektur 66 ID. EntityTypeDAC public EntityTypeEntity GetEntityType(Type type) Gibt die EntityTypeEntity-Entität zu einem Typ zurück. Dabei ist kein Zugriff auf die Datenbank nötig, da sich alle registrierten Typen in einem Cache befinden, welcher in der Methode InitializeEntityTypes() (siehe unten) befüllt wird. public Type GetTypeToEntityType(EntityTyp eEntity EntityType) Gibt den Typ zu einer EntityTypeEntity-Entität zurück. Dabei ist kein Zugriff auf die Datenbank nötig, da sich alle registrierten Typen in einem Cache befinden, welcher in der Methode InitializeEntityTypes() (siehe unten) befüllt wird. public void InitializeEntityTypes( Database, List<IBusinessObjectDAC>) Diese Methode muss bei jeder ThemiSyncerweiterten IBOF ausgeführt werden, Applikation falls dort einmalig ThemSync- Funktionalität benötigt wird. Sie läuft alle Einträge der übergebenen (List<IBusinessObjectDAC>) Liste durch und überprüft, ob dazu bereits ein Eintrag in der Datenbank (Database) existiert. Ist dies der Fall, so wird dieser in einen Cache geladen, andernfalls wird er vorher erstellt und persistiert. Befindet sich in der Datenbanktabelle SystemInfo ein Eintrag CleanEntityTypes mit dem Wert True, so werden nicht-referenzierte Einträge gelöscht und neu erstellt. Dies ist bei einer Modelländerung nötig. private void createAllChangeTrackingData(D Diese Methode erstellt für alle persistierten Softwarearchitektur atabas, List<IBusinessObjectDAC>) 67 Instanzen der übergebenen Typen (List<IBusinessObjectDAC>) eine ChangeTrackingEntity-Entität in der Datenbank (Database) falls diese nicht existiert. Befindet sich in der Datenbanktabelle SystemInfo ein Eintrag CleanEntityTypes mit dem Wert True, so wird diese Methode von der vorher beschriebenen Methode InitializeEntityTypes() aufgerufen. private void updateResolutionSequence( Database, List<IBusinessObjectDAC>) In dieser Methode Reihenfolge der wird die hierarchische Übergebenen Typen (List<IBusinessObjectDAC>) berechnet um bei Importvorgängen Probleme mit Fremdschlüsseln zu vermeiden (siehe 15.3.2). 17.3 Konfiguration Im folgenden Abschnitt werden die Konfigurationsklassen von ThemiSync näher beschrieben, welche dem Anwendungsentwickler für die unterschiedlichen Synchronisationsszenarien zur Verfügung stehen. Alle diese Konfigurationen werden in der Datenbank persistiert und dienen als Konfigurations-Vorlagen, wodurch es möglich ist beliebig viele Konfigurationen vorzubereiten. Abbildung 24 gibt einen Überblick über die Klassen, welche für die Konfiguration relevant sind. Softwarearchitektur 68 Abbildung 24: Konfiguration Technisches Klassendiagramm 17.3.1 Allgemeine Struktur Die Konfigurationen für einen atomaren in sich abgeschlossenen Synchronisationsvorgang werden in einer sogenannten ConfigurationGroupEntity Entität gekapselt. Eine ConfigurationGroupEntity Entität besitzt folgende relevante Attribute: Name Eine eindeutige Bezeichnung der Konfigurationsgruppe. Description Eine informative Beschreibung der Konfigurationsgruppe. Softwarearchitektur 69 Eine ConfigurationEntity Entität beschreibt eine Vorlage für die Synchronisierung einer einzelnen Entitäts-Klasse. Sie dient als Basisklasse sowohl für Export- und Importkonfigurationen und besitzt folgende relevante Attribute: ConfigurationGroupID Die Referenz auf die zugehörige ConfigurationGroupEntity Entität. EntityTypeID Da jede ConfigurationEntity Entität als Vorlage für eine bestimmte EntitätsKlasse definiert wird, ist eine Referenz auf die entsprechende EntityTypeEntity Entität notwendig. Description Eine informative Beschreibung der Konfiguration. SqlWhereClause Dieses Attribut ist ein elementares Konstrukt zum Filtern der Export- oder Importdaten, welches SQL Code enthält, welcher auf die entsprechende Datenbank direkt angewandt wird. Obwohl die Konfiguration dadurch datenbankabhängigen Code Datenbanksystemunabhängigkeit enthält, beeinträchtigt von ThemiSync nicht, dies die da für alle unterschiedlichen Anwendungsszenarien eine passende Konfiguration erstellt werden kann. Um mit einer einzigen Konfiguration möglichst viele Fälle abdecken zu können, bietet das Attribut SqlWhereClause die Möglichkeit mittels der Template-Engine NVelocity [San 09] Vorlagen zu erstellen. Der dadurch entstandene SQL Code filtert die Daten anhand einer WHEREKlausel [KemEik 06], welche mit einem entsprechenden SELECT-Statement [KemEik 06] konkateniert wird. SqlJoinStatement Dieses Attribut dient zum Tabellenübergreifenden Filtern von Export- oder Importdaten, welches analog zum SqlWhereClause Attribut verwendet werden kann. UseTombstoneEntities Mit diesem Attribut wird angegeben, ob beim Export- oder Importvorgang gelöschte Entitäten berücksichtigt werden. Damit ist es möglich das Entfernen von Entitäten beim Synchronisationsvorgang zu verhindern. Softwarearchitektur 17.3.2 70 Export Struktur Für die Steuerung von Export-Vorgängen sind ExportConfigurationEntity Entitäten zuständig. ExportConfigurationEntity Entitäten besitzen keine weiteren Ausprägungen im Vergleich zu ConfigurationEntity Entitäten, trotzdem ist eine Markierung als Exportkonfiguration von fundamentaler Bedeutung für ThemiSync, um die Konfigurationen unterscheiden zu können. 17.3.3 Import Struktur Eine ImportConfigurationEntity Entität dient als Konfiguration für Importvorgänge und erweitert eine ConfigurationEntity Entität mit folgenden Attributen: ImportRuleID Die gewählte Einstellung entscheidet darüber, ob bei einem Konflikt während des Importierens die betroffene Entität der Ziel-Replica überschrieben wird (Overwrite), erhalten bleibt (KeepExisting) oder von der Anwendungslogik der Applikation verarbeitet wird (ApplicationDefined). PreImportActionID In manchen Situationen ist es nötig, alle bereits existierenden Entitäten der Ziel-Replica vor dem Datenimport zu löschen (Delete). Standardmäßig wird allerdings keine Aktion durchgeführt (Nothing). Über eine Entität vom Typ ConfigurationGroupMapping kann zu einer ExportKonfiguration eine passende Import-Konfiguration definiert werden. Beim Importvorgang werden die exportierten ConfigurationGroupEntity Entitäten durchlaufen und jeweils durch die zugeordnete ConfigurationGroupEntity Entität importiert. Die Zuordnung zwischen Export- und Importkonfigurationsgruppen erfolgt aus Benutzerfreundlichkeitsgründen über das Attribut ExportConfigurationGroupName. Um nun die exportiere Konfigurationsgruppe einer Importkonfigurationsgruppe zuzuordnen verweist das Attribut ConfigurationGroupID auf die entsprechende ConfigurationGroupEntity Entität. Softwarearchitektur 17.4 71 Synchronisation Im folgenden Abschnitt wird auf die verschiedenen Bereiche und Phasen der Synchronisation eingegangen. 17.4.1 Datenselektion Unter Datenselektion wird zum Einen die Filterung der zu exportierenden Daten aus der Quell-Replica und zum Anderen die Filterung der zu importierenden Daten aus dem Transportcontainer verstanden. Die Steuerung der Datenselektion obliegt den vom Entwickler zu erstellenden ImportEntity- beziehungsweise ExportEntityEntitäten. Die Attribute SqlWhereClause und SqlJoinStatement der jeweiligen Konfigurations-Entität selektieren über einen IBOF WhereFinder17 die gewünschten Daten. Um die Import- beziehungsweise Export-konfigurationen möglichst flexibel zu halten, besteht die Möglichkeit in der Property SqlWhereClause NVelocityVariablen zu verwenden. Über die öffentliche Methode RegisterVelocityVariable() der Klasse VelocityManager können applikationsseitig die benötigten Variablen registriert werden. Diese Methode erhält als Parameter einen String, welcher die Variablenbezeichnung definiert und ein Delegate [Tro 07], welches die dynamisch auszuführende Methode beschreibt. Durch die Verwendung von Delegates ist es möglich, während des Export- beziehungsweise Importvorgangs Methoden auszuführen, welche in der ThemiSync-Erweiterten Applikation implementiert wurden. ThemiSync bietet für jede Konfigurationsgruppe einen eigenen VelocityManager. Außerdem können Velocity-Variablen global registriert werden. Diese Variablen stehen allen Konfigurationsgruppen einer ThemiSyncImportbeziehungsweise ThemiSyncExport-Entität während des Synchronisationsvorganges zur Verfügung. Folgendes Beispiel beschreibt einen Selektionsvorgang beim Exportieren und verwendet ThemiSync Objekte, die in Abbildung 25 und Abbildung 26 illustriert sind: 17 IBOF WhereFinder ist ein von IBOF zur Verfügung gestelltes Werkzeug um über eine Where- Klausel und ein Join-Statement BusinessObject Entitäten zu filtern. Softwarearchitektur 72 ExportConfigurationEntityObj : ExportConfigurationEntity ... SqlWhereClause : string = TypB.id in (#foreach($var in $IdLst) $var, #end 6) SqlJoinStatement : string = JOIN TypB on TypB.x = TypA.x EntityTypeObj : EntityTypeEntity = TypA ... Abbildung 25: Beispiel für ein ExportConfigurationEntity Objekt VelocityManagerObj : VelocityManager velocitynamePropertynameDictionary = "IdLst" -> {1,2,3} Abbildung 26: Beispiel für ein VelocityManager Objekt Diese Exportkonfiguration soll alle Datensätze der Datenbanktabelle vom TypA selektieren, welche einen Fremdschlüssel in der Tabelle TypB und dort die Datensatz-ID 1,2,3 oder 6 haben. Dies geschieht in zwei Schritten. Zuerst wird mit dem Aufruf VelocityManagerObj.Evaluate(ExportConfigurationEntityObj.SqlWhereC lause) die Property SqlWhereClause ausgewertet. Das Ergebnis (“TypB.id in (1,2,3,6)”) und das SqlJoinStatement wird an einen IBOF WhereFinder übergeben. Dieser kennt den Typ durch das EntityTypeObj und gibt das Ergebnis zu folgendem SQL Query zurück: Select * FROM TypeA JOIN TypB on TypB.x = TypA.x WHERE TypB.id in (1,2,3,6). 17.4.2 Export Folgende Abbildung 27 zeigt ein Klassendiagramm, in welchem die wichtigsten Klassen, die für den Exportvorgang eine bedeutende Rolle spielen, dargestellt werden. Softwarearchitektur 73 Abbildung 27: Klassendiagramm Export Um einen Exportvorgang ThemiSyncExport erstellt einzuleiten, werden. Diese muss bietet eine Instanz mehrere der Klasse unterschiedliche Konstruktoren an, mit denen die Quelldatenbank in Form einer Instanz der IBOFKlasse Database und der Pfad für die Exportdatei definiert werden kann. Die Klasse enthält eine Liste mit dem Namen ConfigurationGroups, welche mit den zu exportierenden Konfigurationsgruppen gefüllt werden muss. Diese Liste wird Softwarearchitektur 74 beim Ausführen der Methode Start() durchlaufen und verarbeitet. Dabei wird für jeden Listeneintrag eine eigene Transport-Datenbank erstellt, welche durch eine ExportAction-Instanz befüllt wird. Um eine Instanz der Klasse ExportAction zu erstellen, müssen dem Konstruktor folgende Parameter übergeben werden: Database sourceDatabase Als Parameter wird eine Instanz der IBOFKlasse Database, welche als Schnittstelle zur Quelldatenbank dient, benötigt. Database destinationDatabase Als Parameter wird eine Instanz der IBOFKlasse Database, welche als Schnittstelle zur Zieldatenbank dient, benötigt. ConfigurationGroupEntity configurationGroup Als Parameter wird eine Instanz der Klasse ConfigurationGroupEntity benötigt, welche die zu exportierende Konfigurationsgruppe beschreibt. TSVelocityManager velocityManager Als Parameter wird eine Instanz der Klasse TSVelocityManager benötigt, welche zum Auswerten der SQL-Statementes benötigt wird. Die Hauptfunktionalität eines Exportvorgangs liegt in der Methode public void Export() welche sich in der Klasse ExportAction befindet. Diese Methode wird im folgenden Abschnitt detailliert behandelt: Der vollständige Export-Prozess wird innerhalb von Datenbank-Transaktionen atomar durchgeführt. Zu Beginn werden globale System-Informationen des exportierenden ThemiSync-Systems als Entitäten der Klasse SystemInfoEntity in die Export-Datenbank gespeichert. Diese dienen zur Kompatibilitäts-Kontrolle während Softwarearchitektur 75 des Import-Vorganges. Weiters wird auch der Name der Konfigurationsgruppe protokolliert, um beim Konfigurationsgruppe Importieren automatisiert verwenden die zugehörige zu Import- können (siehe ConfigurationGroupMappingEntity in 17.3). Anschließend werden alle ExportConfigurationEntity Entitäten der ConfigurationGroupEntity Entität einzeln durchlaufen und auf jeder dieser Entitäten die Methode FindUntyped() aufgerufen. Diese von IBOF bereitgestellte Methode sucht anhand übergebener Parameter die passenden Einträge. Da zur Compile-Zeit die Typen der ExportConfigurationEntity Entitäten nicht bekannt sein können, muss diese generische Methode verwendet werden, welche Entitäten des Typs AbstractBusinessObject zurückgibt. Die zurückgelieferten AbstractBusinessObjects werden in die Export-Datenbank mit deren angepassten ChangeTrackingEntity Entitäten kopiert. Falls bei einer ExportConfigurationEntity Entität die boolesche Variable UseTombstoneEntities den Wert True enthält, werden auch die für diese ExportKonfiguration gefundenen TombstoneEntity Entitäten in die Export-Datenbank kopiert. Nachdem eine komplette ConfigurationGroupEntity Entität, wie im vorigen Abschnitt beschrieben, verarbeitet wurde, wird in der Start() Methode der Klasse ThemiSyncExport anschließend die resultierende Export-Datenbank in einen Filebasierten Transport-Container gespeichert. Ein Transport-Container kann mehrere Export-Datenbanken enthalten. Um beim Einsatz der File-basierten Datenbanksysteme flexibel zu bleiben, werden ein Transport-Container und dessen Inhalte im Hauptspeicher in Form von Objektinstanzen dargestellt. Mit diesem Konzept ist es über die Implementierung der Klasse AbstractDBWrapper jederzeit möglich, die angebotenen Datenbanksysteme für die Export-Datenbank zu erweitern. Die aktuelle Implementierung von ThemiSync bietet mit der Klasse SqlCeDBWrapper die Verwendung von Microsoft SQL Compact Datenbanken an. Softwarearchitektur 76 Als Container für die exportierten Datenbanken agiert die Klasse DBArchive, welche die Möglichkeit bietet ihren Inhalt als ZIP-Archiv18 im Dateisystem abzulegen. Folgende Darstellung in Abbildung 28 verdeutlicht die beschriebene ContainerStruktur anhand eines Klassendiagramms. 18 Das Dateiformat ZIP dient zum Komprimieren von mehreren Dateien und Dateistrukturen in einer einzelnen Datei. Softwarearchitektur 77 Abbildung 28: Datenmodell Transport-Container Abbildung 29 beschreibt den Export-Vorgang anhand eines Sequenzdiagramms. Die Abbildung wird aus Gründen der Übersichtlichkeit im Querformat dargestellt. Softwarearchitektur Abbildung 29: Sequenzdiagramm zum Visualisieren des Exportvorgangs (Querformat) 78 Softwarearchitektur 17.4.3 79 Import Folgende Abbildung 30 visualisiert die wichtigsten Klassen für den Importvorgang anhand eines Klassendiagramms. Abbildung 30: Klassendiagramm Import Softwarearchitektur 80 Ein Importvorgang kann mit einer Instanz der Klasse ThemiSyncImport gestartet werden. Folgende Parameter können dem Konstruktor übergeben werden: Database destinationDatabase Als Parameter wird eine Instanz der IBOFKlasse Database, welche als Schnittstelle zur Zieldatenbank dient, benötigt. string sourceArchivePath Als Parameter wird der Pfad zum exportieren Transport-Container benötigt (siehe 17.4.2). Wird für den Parameter destinationDatabase kein Wert übergeben, so wird die Standarddatenbank als Ziel-Replica verwendet. Der Importvorgang wird mit dem Aufruf der Methode Start() durchgeführt. Dabei wird für jede Datenbank, die sich im Transport-Container befindet, eine neue Instanz der Klasse ImportAction erstellt. Die Methode Import() der Klasse ImportAction führt den Importvorgang für die Entitäten der betreffenden Datenbank durch. Die dafür benötigten Informationen werden dem Konstruktor von ImportAction hierfür übergeben. Zu Beginn werden die SystemInfoEntity Entitäten der Quell- und Ziel-Replicas ausgelesen und verglichen, sodass sichergestellt werden kann, ob die Datenbankund ThemiSync-Versionen kompatibel zueinander sind. Weiters wird der Name der Konfigurationsgruppe ausgelesen und durch ConfigurationGroupMappingEntity Entitäten die zugehörige Import-Konfigurationsgruppe gesucht. Wenn eine solche passende Konfigurationsgruppe gefunden wurde, dann werden in der Methode Import() zusätzlich folgende drei Methoden ausgeführt: 1. runPreImportActions() 2. runTombstoneActions() 3. runImportActions() Durch die Methode runPreImportActions() können spezielle Aktionen durchgeführt werden, bevor der eigentliche Importvorgang begonnen hat. Derzeit werden von ThemiSync lediglich die Aktion Nothing und Truncate unterstützt. Truncate ermöglicht das vollständige Löschen der betreffenden Tabellen. Softwarearchitektur 81 Die Methode runTombstoneActions() dient zum Synchronisieren von gelöschten Entitäten. Das bedeutet, dass eventuell Entitäten auf der Ziel-Replica entfernt werden, wenn sie auch auf der Quell-Replica entfernt und synchronisiert wurden. Das eigentliche Importieren der Entitäten, sowie die Konfliktüberprüfung erfolgt in der Methode runImportActions(). Falls ein Konflikt auftretet und eine benutzerdefinierte Konfliktbehandlung konfiguriert wurde, dann wird folgendes Ereignis eintreten: EventHandler<ConflictEventArgs> Conflict; Das Ereignis Conflict wird immer dann ausgelöst, wenn beim Importieren ein Synchronisationskonflikt auftritt. Beim Auslösen des Conflict Ereignisses wird eine Instanz der Klasse ConflictEventArgs mitgesendet, welche folgende Properties besitzt: AbstractBusinessObject SourceEntity Analoge Entität zur DestinationEntity, welche aus dem Transport-Container stammt. Dies ist die neue Entität, die aus der Quell-Replika stammt. AbstractBusinessObject DestinationEntity Analoge Entität zur SourceEntity, welche bereits in der Ziel-Replica existiert. Guid SourceReplicaID Diese Property enthält die ID der Quell-Replica. Guid DestinationReplicaID Diese Property enthält die ID der ZielReplica. bool ImportSourceEntity Diese Property entscheidet, ob die betreffende Quell-Entität importiert wird (True), oder die bestehende ZielEntität erhalten bleibt (False). Softwarearchitektur 82 bool Cancel Wenn diese boolesche Property den Wert True erhält, dann wird der komplette Synchronisationsvorgang abgebrochen. Mit Hilfe der Properties der Klasse ConflictEventArgs kann in der AnwendungsLogik entschieden werden, ob die SourceEntity importiert wird, oder nicht. Falls die Entität aus der Quell-Replica importiert werden soll, muss die Property ImportSourceEntity den Wert True bekommen, anderenfalls bleibt die Entität aus der Ziel-Replica erhalten. Wenn die Property Cancel den Wert True erhält, dann wird der komplette Synchronisationsvorgang abgebrochen und eine ImportCancelledException geworfen. Folgende Abbildung 31 zeigt ein Sequenzdiagramm, welches einen typischen Importvorgang abbildet. Die Abbildung wird aus Gründen der Übersichtlichkeit im Querformat dargestellt. Softwarearchitektur Abbildung 31: Sequenzdiagramm zum Visualisieren des Importvorgangs (Querformat) 83 Softwarearchitektur 17.4.4 84 Datenbank-Konfliktbehandlungen Um die Konsistenz der Datenbank zu gewährleisten werden häufig Fremdschlüssel verwendet. Dadurch entstehen allerdings Abhängigkeiten der Tabellen untereinander, wodurch manipulative Operationen wie Einfügen, Bearbeiten und Löschen von Datensätzen ohne entsprechende Behandlung häufig nicht durchgeführt werden können. Eine naheliegende Lösung dieses Problems wäre die vorübergehende Deaktivierung der Fremdschlüssel während der Transaktion. Dies führt unter Microsoft SQL Server 2008 allerdings zum vollständigen Sperren von allen Tabellen, auf welche sich die Fremdschlüssel beziehen. Um dieses Verfahren bei ThemiSync anzuwenden, muss allerdings der Entwickler selbst die Fremdschlüssel aushängen und ThemiSync dabei die Transaktion mitliefern. Ein einfaches Beispiel für das Deaktivieren der Fremdschlüssel gibt folgender CodeAusschnitt: String path = ""; ThemiSyncImport themiSyncImport = null; Database dbSession = DatabaseManager.Instance.Database.BeginTransaction(); try { // disable the foreign key // FK_Trainer_ChefTrainer dbSession.ExecuteNonQuery("ALTER TABLE Trainer NOCHECK CONSTRAINT FK_Trainer_ChefTrainer"); themiSyncImport = new ThemiSyncImport(dbSession, path); themiSyncImport.Start(); // enable the foreign key // FK_Trainer_ChefTrainer dbSession.ExecuteNonQuery("ALTER TABLE Trainer CHECK CONSTRAINT FK_Trainer_ChefTrainer"); dbSession.CommitTransaction(); } catch { dbSession.RollBackTransaction(); throw; } In diesem Code-Ausschnitt wird ein Datenbank-Archiv, dessen Pfad in der StringVariable path steht, importiert. Dabei handelt es sich um eine rekursive Struktur, welche Daten von Trainern beinhalten. Die rekursive Struktur entsteht dadurch, dass Softwarearchitektur 85 manche Trainer eine übergeordnete Rolle spielen und dabei Chef-Trainer von anderen Trainern sind. Dies wurde mit einem rekursiven Verweis auf dieselbe Tabelle, namens Trainer realisiert Damit nun keine Konflikte während des Import-Vorganges auftreten, wird vor dem Import-Vorgang mit der Methode dbSession.ExecuteNonQuery() das ALTER TABLE SQL-Statement mit der Option NOCHECK CONSTRAINT ausgeführt, um den genannten Fremdschlüssel zu deaktivieren. Nach dem Importieren wird dieser analog dazu mit der Option CHECK CONSTRAINT allerdings wieder aktiviert. Da bei der vorher genannten Technik die Nebenläufigkeit allerdings stark eingeschränkt werden kann, haben wir uns für eine weitere Lösung entschieden. Unsere Lösung besteht aus zwei Kernbereichen: 1. Die unterschiedlichen Entitäts-Typen werden in einer vorgegebenen Reihenfolge importiert. 2. Durch spezielle Ereignisse kann der Entwickler vor und nach dem Importvorgang Entitäten bearbeiten, sodass Konflikte vermieden werden können. Ad 1 Standardmäßig wird eine Import-Reihenfolge gewählt, welche automatisch von ThemiSync mit einem Algorithmus (siehe 15.3.2) berechnet wurde, sodass möglichst keine Konflikte beim Importieren auftreten. Zusätzlich besteht aber auch die Möglichkeit die Reihenfolge temporär selber zu beeinflussen. Dies ermöglicht die Property ImportConfigurationEntityComparer der Klasse ThemiSyncImport, mit welcher eine benutzerdefinierte Vergleichsmethode hinterlegt werden kann, die das IComparer Interface implementiert. Ad 2 Die Klasse ThemiSyncImport ermöglicht anhand von unterschiedlichen Ereignissen das Vermeiden von Konflikten, welche einen Import-Vorgang unmöglich machen würden. Dafür stehen folgende Ereignisse zur Verfügung: 1. BeforeDelete 2. PreImport 3. PostImport Softwarearchitektur Event-Handler 86 für das Ereignis BeforeDelete können dabei direkt in ThemiSyncImport registriert werden und gelten übergreifend für alle Entitäts-Typen und Konfigurations-Gruppen. Die Ereignisse PreImport und PostImport müssen für jeden betreffenden EntitätsTyp unabhängig registriert werden. Das ermöglichen folgende Methoden indem sie eine Instanz der Klasse ImportHandler passend zum übergebenen Entitäts-Typ zurückliefern. public ImportHandler GetImportHandler(short entityTypeID) public ImportHandler GetImportHandler(EntityTypeEntity entityType) Die Klasse ImportHandler bietet dann die Properties PreImport und PostImport an, wodurch individuelle Event-Handler registriert werden können. Im Folgenden werden nun die einzelnen Ereignisse im Detail betrachtet. BeforeDelete Durch das Ereignis BeforeDelete können vor dem Löschen einer Entität, Verweise auf diese ebenfalls gelöscht werden, damit der Löschvorgang fehlerfrei durchgeführt werden kann. Eine Instanz der Klasse BeforeDeleteEventArgs wird beim Auslösen des BeforeDelete Ereignisses mit gesendet, welche folgende Properties besitzt: List<AbstractBusinessObject> Entities Die Liste aller Entitäten, die in der ganzen Konfigurationsgruppe gelöscht werden. bool Cancel Wenn diese boolesche Property den Wert True erhält, dann wird der komplette Synchronisationsvorgang abgebrochen. Wenn das Flag Cancel den Wert True erhält, dann wird der Importvorgang abgebrochen und eine ImportCancelledException geworfen. Softwarearchitektur 87 PreImport Dieses Ereignis tritt kurz vor dem Importieren einer Entität auf, die ThemiSync für das Importieren gekennzeichnet hat. Dem Ereignis wird eine Instanz der Klasse PreImportEventArgs mit gesendet, welche folgende Properties besitzt: AbstractBusinessObject Entity Die Entität, welche gerade importiert werden sollte. bool IsIncludedInPostImportEvent Wenn diese boolesche Property auf den Wert True gesetzt wird, dann wird die Entität, welche gerade importiert werden sollte, für das PostImport Ereignis vorgemerkt und dessen Entitäts-Liste eingereiht. Mit diesem Ereignis werden üblicherweise Verweise, welche während des ImportVorgangs zu Problemen führen, temporär gelöscht. Durch das Setzen des Flags IsIncludedInPostImportEvent auf True wird die Entität später beim Ereignis PostImport mit gesendet, wodurch der Verweis wieder neu gesetzt werden kann. PostImport Nachdem alle Entitäten importiert oder behandelt wurden, wird das PostImport Ereignis per Konfigurationsgruppe einmalig ausgeführt. Dabei werden alle Entitäten der Konfigurationsgruppe, welche zuvor im PreImport Ereignis anhand des Flags IsIncludedInPostImportEvent markiert wurden, mitgeführt, sodass diese nachbehandelt werden können. Eine Instanz der Klasse PostImportEventArgs liefert dabei diese Entitäten als Liste in folgender Form: List<AbstractBusinessObject> Entities Die Liste aller Entitäten, die in der ganzen Konfigurationsgruppe während des PreImport Ereignisses für die Nachbehandlung vorgemerkt wurden. Softwarearchitektur 88 Üblicherweise werden die Verweise, welche während des PreImport Ereignisses gelöscht wurden, in diesem Ereignis wieder neu gesetzt, sodass die Entitäten ihren vorherigen Zustand zurück erhalten. Mit folgendem Code-Ausschnitt wird nun wieder dieselbe Problemstellung, wie im vorherigen Code-Ausschnitt behandelt. Dabei handelt es sich um das Synchronisieren von Trainer-Daten, welche zusätzliche eine rekursive Struktur besitzen. Die Rekursion ergibt sich daraus, dass die Tabelle Trainer eine Spalte ChefTrainer besitzt, um die Trainerstruktur hierarchisch abbilden zu können. Softwarearchitektur 89 String path = ""; Database dbSession = DatabaseManager.Instance.Database.BeginTransaction(); ThemiSyncImport themiSyncImport = null; Dictionary<Guid, Guid> chefTrainerDictionary = new Dictionary<Guid, Guid>(); try { themiSyncImport = new ThemiSyncImport(dbSession, path); ImportHandler importHandlerTrainer = themiSyncImport.GetImportHandler( EntityTypeDAC.Instance.GetEntityType( TrainerDAC.Instance.BusinessObjectType ) ); importHandlerTrainer.PreImport += new EventHandler<PreImportEventArgs>( delegate(object o, PreImportEventArgs e) { TrainerEntity entity = e.Entity as TrainerEntity; if (entity.ChefTrainerObj != null) { chefTrainerDictionary.Add(entity.TrainerID, entity.ChefTrainerID); entity.ChefTrainerObj = null; e.IsIncludedInPostImportEvent = true; } } ); importHandlerTrainer.PostImport += new EventHandler<PostImportEventArgs>( delegate(object o, PostImportEventArgs e) { foreach (AbstractBusinessObject abstractObject in e.Entities) { TrainerEntity entity = abstractObject as TrainerEntity; entity.ChefTrainerID = chefTrainerDictionary[entity.TrainerID]; } } ); themiSyncImport.Start(); dbSession.CommitTransaction(); } catch { dbSession.RollBackTransaction(); throw; } Die Variable path verweist auf den Export-Container, der bereits exportierten Daten. Die Methode GetImportHandler, welche die ThemiSyncImport Instanz anbietet, Softwarearchitektur 90 liefert den ImportHandler, der für die Trainer-Entitäten zuständig ist zurück. An diesem ImportHandler werden nun Behandlungen für die Ereignisse PreImport und PostImport registriert. Dabei werden anonyme Methoden verwendet, da die Behandlungen nur für genau diese Ereignisse verwendet werden. Im PreImport Ereignis wird überprüft, ob die mitgelieferte Entität einen Verweis auf den Chef-Trainer besitzt. Falls dies nicht der Fall ist, dann wird die Behandlung beendet und die Entität ohne Änderung importiert. Falls die Entität allerdings einen solchen Verweis besitzt, dann wird der Verweis zwischengespeichert und in der Entität entfernt. Das Flag IsIncludedInPostImportEvent wird auf True gesetzt, damit die Entität im PostImport Ereignis wieder mitgeliefert wird, sodass die Änderung wieder rückgängig gemacht werden kann. Im PostImport Ereignis werden alle vorgemerkten Entitäten als Liste mitgeliefert und durchlaufen. Dabei werden alle vorher entfernten Verweise auf die Chef-Trainer wieder hergestellt. Qualitätssicherung Das Hauptziel dieses Projektes war es, eine Synchronisationsmöglichkeit für diverse Daten der Software TrainingStudio innerhalb beliebig vieler Instanzen synchron zu halten. Wie bereits in vorhergehenden Kapiteln beschrieben wurde, ist die Vorgängerversion auf dem Markt bereits gut vertreten und die neue Version, welche die Vorgängerversion ablösen soll, soll noch mehr Klientel anwerben. Das bedeutet, dass das TrainingStudio zusammen mit ThemiSync keine „langsame Einführungsphase“ erleben wird, sondern bereits von Anfang an für alle TrainingStudio–Kunden der Firma InfPro fehlerfrei funktionieren muss. Neben allgemeinen Gründen für ein gutes Qualitätsmanagement bei der Softwareentwicklung, fordert dieser Umstand diesbezüglich besondere Sorgfalt. Qualitätssicherung wurde während des gesamten Projektverlaufs besonders fokussiert. Folgende Grafik (Abbildung 32) gibt einen Überblick über die relevanten Softwareentwicklungsphasen und den eingesetzten qualitätssicherungsspezifischen Merkmalen, welche in folgenden Kapiteln detailliert beschrieben werden. Qualitätssicherung 92 Analyse Entwurf Implementierung Anforderungstest Integration Designtest Einsatz Funktionstest Wartung Systemtest Abbildung 32: Projektphasen Qualitätsmanagement 18 Analyse Die Qualitätssicherung beginnt bereits in der Planungsphase eines Projektes. Dabei gilt es die Anforderungen auszuarbeiten und in Zusammenarbeit mit dem Auftraggeber exakt und testfähig zu formulieren. Nach dem Erhalt des Pflichtenheftes und der klaren Abgrenzung des Aufgabenbereichs wurde vor Konzeptionsbeginn in mehreren Sitzungen mit dem Auftraggeber überprüft, ob beiderseits (Auftraggeber, Auftragnehmer) alles richtig und sinngemäß übereinstimmend verstanden wurde. Dabei standen neben Funktionsvollständigkeit, Beschreibungsvollständigkeit, Begriffseindeutigkeit, Widersprüche in Anforderungen, und anderen wichtigen Merkmalen der Anforderungsdefinition auch firmeninterne Konventionen bezüglich Sourcecode, Tabellenbezeichnungen und allgemeine Usancen zur Debatte. Um die Funktionsvollständigkeit wurden verschiedene Szenarien der Anwendungsfälle (siehe 12) detailliert durch besprochen und effektuiert. 19 Entwurf Bei der Entwurfsphase ging es hinsichtlich Qualitätssicherung vor allem darum, die Abläufe, Schnittstellen und Funktionalitäten im Detail abzuklären. Hier wurden die verwendeten Techniken fixiert und anhand diverser Beispielimplementierungen überprüft/getestet, ob sie für den benötigten Einsatz geeignet sind. Auch hier wurde zusätzlich im Rahmen von Besprechungen und Progress Reviews vom Auftraggeber zur Qualitätssicherung beigetragen. Qualitätssicherung 20 93 Implementierung Die Entwicklungsphase der Implementierung benötigt ein besonders großes Maß an Qualitätsmanagement, da besonders hier viele Fehler passieren können. Folgende Werkzeuge und Techniken trugen während der Umsetzung des Projektes zur Qualitätssicherung bei. 20.1 Extreme Programming (XP) Der Softwareentwicklungsprozess von ThemiSync lief in vielen Aspekten nach dem agilen Ansatz des Extreme Programmings ab. Kurz beschrieben handelt es sich dabei um eine Technik, welche es für kleine Teams ermöglicht, langlebige Software zu erstellen und auf vage und sich rasch ändernde Anforderungen reagieren zu können. Konkret kamen folgende XP-Elemente zum Einsatz: Kurze Iterationen In mehr oder weniger regelmäßigen und relativ engen Zeitabständen wurden Sitzungen mit dem Auftraggeber abgehalten und dabei zum Einen der aktuelle Stand präsentiert, sowie Codereviews vom Auftraggber durchgeführt (siehe 20.2) und zum Anderen die weiteren Schritte bis zum nächsten Meeting fixiert. Offene Kommunikation im Team Unerlässlich beim Extreme Programming ist die offene Kommunikation im Team. Sofern gemeinsam programmiert wurde (siehe 20.3) war dieses Kriterium ohnehin leicht realisierbar, aber auch andernfalls war das Projektteam ständig in Kontakt und über den Projektstand detailliert informiert. Refactoring Jeder im Projektteam fühlt sich für die Qualität von ThemiSync verantwortlich. Deshalb wurde das System während der Implementierungsphase ständig durch refactorings optimiert. Dabei spielte es keine Rolle von wem der optimierungswürdige Code stammte – es ging darum die Qualität zu erhöhen. Fortlaufende Integration ThemiSync wurde bereits in einer sehr frühen Projektphase partiell in das TrainingStudio integriert. Damit lief es von Beginn an mit dem automatisierten Qualitätssicherung 94 Testverfahren über Unittests (siehe 20.4) und Cruisecontrol (siehe 20.5) mit und stand unter permanenter Kontrolle. 20.2 Codereviews Kritische Codeteile wurden regelmäßig von unserem Auftraggeber durchgesehen und mit Verbesserungsvorschlägen kommentiert. Da unser Auftraggeber und technischer Betreuer – Herr Dipl.-Ing. Hansjörg Haller – ein sehr renommierter und erfahrener Softwareentwickler ist, stellen die zahlreichen Tipps, Vorschläge und Hinweise auf Gefahrenquellen einen sehr wichtigen Bestandteil der Qualitätssicherung von ThemiSync dar. 20.3 Pair-Programming Wo immer es dem Projektteam möglich war und sinnvoll erschien, wurde gemeinsam an einem Computer entwickelt. Pair-Programming bringt einige Vorteile mit sich. Unter Anderem zählen dazu: 20.4 - Höhere Disziplin (Pausen, vereinbarte Konventionen, …) - Besserer Code (durch permanente gegenseitige Kontrolle) - Motivationsfördernd (Im Team machts mehr Spaß als allein) - Mentoring (Wissen wird verteilt) - … Unittests Parallel zur aktuellen Iteration wurden Unittests geschrieben, um die Funktionalität zu automatisieren, sowie dauerhaft und regelmäßig überprüfen zu können. Hierbei kam das Framework NUnit zum Einsatz, welches bei allen Projekten der Firma InfPro verwendet wird. Dadurch wurde auch die Integration in Cruisecontrol (siehe 20.5) ermöglicht. 20.5 Cruisecontrol Cruisecontrol ist ein Java-basiertes System, welches dazu dient während eines Softwareentwicklungsprozesses kontinuierliche Erstellungsprozesse automatisiert anzustoßen. Dadurch werden neue Softwareelemente bei jedem Check in das Qualitätssicherung 95 gesamte System integriert und das Zusammenspiel der Komponenten über Unittests automatisch getestet. Dieses Werkzeug wird von der Firma InfPro eingesetzt und uns von Beginn an zur Verfügung gestellt. Bereits die Tatsache, dass jeder Entwickler der Firma sofort über einen fehlerhaften Build informiert wird sorgt dafür, dass man sehr genau auf die Richtigkeit seines Codes achtet. 21 Integration Da ThemiSync, wie bereits erwähnt kontinuierlich in das Zielsystem (TrainingStudio) integriert wurde und das Gesamte dadurch einer ständigen Qualitätskontrolle unterlag, waren bei der finalen Integration keine zusätzlichen qualitätssicherungsfördernden Maßnahmen nötig. 22 Einsatz & Wartung Die Qualitätssicherung während des Einsatzes und der Wartung von ThemiSync liegt bei der Firma InfPro. Im Rahmen des Projektes wird die Software in das firmeninterne Unittesting-System integriert und somit automatisiert getestet. Benutzerhandbuch 23 Einleitung Dieses Benutzerhandbuch dient als Hilfestellung und Nachschlagewerk für Entwickler, welche ThemiSync zur Datensynchronisation verwenden möchten. Es beschreibt anhand eines einfachen Beispiels, welches auf einer bereits bestehenden IBOF-Applikation aufbaut, wie die Synchronisations-API eingesetzt werden kann. Dabei wird auf alle nötigen Vorbereitungsarbeiten, Konfigurationsmöglichkeiten und den Umgang mit den Schnittstellen detailliert eingegangen. 24 24.1 Beispielapplikation Einleitung Die Beispielapplikation ist sehr einfach gehalten und besteht aus nur vier Klassen. Trotzdem bietet sie die Möglichkeit, alle Standard- und Spezialfälle bezüglich ThemiSync zu erklären. Als zugrundeliegendes Datenbanksystem wird Microsoft SQL Server 2008 eingesetzt, während für Export- und Importdaten Microsoft SQL CE verwendet wird. Folgendes UML Diagramm in Abbildung 33 zeigt die Grundstruktur der Geschäftslogik: Benutzerhandbuch 98 Abbildung 33: Beispielapplikation UML Diagramm 24.2 Benötigte DLLs Um ThemiSync in der Beispielapplikation verwenden zu können, müssen folgende DLLs referenziert werden: - InfPro.ThemiSync.BusinessObjects.dll - InfPro.ThemiSync.dll - InfPro.ThemiSync.Exceptions.dll - InfPro.ThemiSync.Synchronization.dll - InfPro.ThemiSync.Utils.dll - NVelocity.dll - ICSharpCode.SharpZipLib.dll - InfPro.Databases.SQLServerCEDriver.dll (Transportdatenbank) Benutzerhandbuch 25 99 ThemiSync Konfigurationstool Für eine einfache Installation und Konfiguration von ThemiSync-erweiterten IBOF Projekten, steht ein Tool zur Verfügung. Abbildung 34 zeigt einen Screenshot des Tools. Das ThemiSync-Configurationtool erhält alle benötigten Informationen (Connectionstrings, Username, Passwort, …) über die IBOF-Konfigurationsdatei (.boc) welche für jedes IBOF Projekt ohnehin erstellt werden muss. Bevor die Konfigurationsdatei gewählt wurde, ist keine Aktion möglich. Die einzelnen Features des ThemiSync-Configurationtools werden wie folgt in den entsprechenden Abschnitten detailliert beschrieben. Benutzerhandbuch 100 Abbildung 34: ThemiSync Configurationtool 26 26.1 Vorbereitungen (Datenbank, IBOF) Datenbank Die Datenbank eines IBOF-Projektes welches mit ThemiSync erweitert werden soll, muss für das Persistieren der benötigten Metadaten und zur Verwaltung diverser Konfigurationsdaten einige Tabellen bereitstellen. Für eine bessere Übersichtlichkeit im Datenbankmodell bietet sich der Einsatz von Schemata an. Alle ThemiSync-Tabellen müssen sich im Schema „ThemiSync“ befinden. Benutzerhandbuch 101 Folgendes Datenbankmodell in Abbildung 35 zeigt die zwingend zu verwendende Tabellenstruktur, welche zusätzlich zu denen von der Applikation verwendeten Tabellen in der Anwendungsdatenbank erstellt werden muss. Abbildung 35: ThemiSync Datenbanktabellen Übersicht Benutzerhandbuch 102 Die Konfigurationstabellen „ImportRule“, „PreImportAction“ und „SystemInfo“ müssen mit folgenden Zeilen befüllt sein: ImportRule ImportRuleID Name 0 Overwrite 1 KeepExisting 2 ApplicationDefined PreImportAction PreImportActionID Name 0 Nothing 1 Delete SystemInfo SystemInfoID Name Value Guid.NewGuid() ThemiSyncVersion Aktuelle Versionsnummer ThemiSync von Guid.NewGuid() DatabaseVersion Aktuelle Versionsnummer des Datenbankschemas Guid.NewGuid() ReplicaID Eindeutige ID der Datenbank (Guid) Tipp: Alle benötigten Tabellen und Datensätze (ausgenommen die Daten der Tabelle SystemInfo) können automatisiert über das Konfigurationstool erstellt werden. Öffnen Sie dazu das Tool und wählen unter dem Reiter „Common“ (im Bereich „Database“) das entsprechende Skript aus (im Normalfall wird es die aktuellste Benutzerhandbuch 103 Version sein). Anschließend klicken Sie auf „execute“ – eine Messagebox informiert Sie über den Verlauf der Installation. 26.1.1 Beispielsapplikation Nach erfolgreicher Erweiterung der Beispielapplikationsdatenbank enthält die Datenbank neben dem Schema „ThemiSync“ folgende Tabellen, die in Abbildung 36 illustriert werden: Abbildung 36: Beispielapplikation Tabellen 26.2 IBOF Für den Einsatz von ThemiSync wurde der IBOF-Generator um einige Einstellungen erweitert. Neben den Standardeinstellungen muss für ThemiSync-erweiterte IBOFProjekte auf Einstellungen geachtet werden, die in folgender Abbildung 37 mit roten Ellipsen gekennzeichnet sind: Benutzerhandbuch 104 Abbildung 37: IBOF Generator 26.2.1 Is Used For Sync (1) Dieses Flag entscheidet global auf Typ-Ebene ob die entsprechenden Daten synchronisiert werden sollen, oder nicht. Bei Hierarchien ist darauf zu achten, dass nur der betreffende Typ markiert werden muss, nicht aber die darunter liegenden generalisierten Klassen (Siehe 26.2.3). 26.2.2 Is used for SyncHash (2) Über dieses Flag können einzelne Spaltenwerte (Properties) von der Generierung des Vergleichs-Hashs (SyncHash) ausgenommen werden. Änderungen an abgewählten Properties werden bei der Synchronisation ignoriert. Damit ist es zum Beispiel möglich die letzte Speicherung zeitlich zu protokollieren aber nur im Falle einer tatsächlichen Wertänderung in einem anderen Datenfeld zu synchronisieren. 26.2.3 Beispielapplikation – IBOF Konfiguration Im Beispiel wird davon ausgegangen, dass alle Klassen synchronisierbar gemacht werden müssen. Es wird daher überall das Flag „Is Used for Sync“ markiert. Da es Applikationsseitig auch User ohne weitere Ausprägung gibt wird dieses auch für den Typ User gesetzt. Wäre dies nicht der Fall, gäbe es nur User-Instanzen von den Typen Athlet und Trainer, müsste man den Typ User von der Synchronisation Benutzerhandbuch 105 ausnehmen, da ThemiSync die Daten auf Typ-Ebene und nicht auf Tabellen-Ebene verwendet. Das Datenfeld ChangedDateTime existiert durch die Klassenhierarchie in allen Typen des Beispiels, und wird Applikationsseitig immer dann aktualisiert, wenn eine Instanz des entsprechenden Typs gespeichert wird – unabhängig davon, ob sich andere Werte tatsächlich geändert haben oder nicht. Diese Property ist also nie entscheidend dafür, ob sich der (applikationsrelevante) Objektzustand geändert hat und sollte daher bei der Synchhash-Generierung außer Acht gelassen werden. Dies wird durch Deaktivierung des Flags „Is used for SyncHash“ bei den entsprechenden Feldern markiert. Die abgeschlossene IBOF Konfiguration unserer Beispielapplikation sieht also folgendermaßen aus: Is used for Sync Is used for SyncHash Athlet AthletID AthleteGroupID Weight AthleteGroup AthleteGroupID TrainerID Name ChangedDateTime Trainer TrainerID Benutzerhandbuch 106 BossTrainerID SportsClub User 27 UserID FirstName LastName Birthdate ChangedDateTime Konfiguration (ThemiSync) Die Konfiguration beziehungsweise von ThemiSync besteht Importkonfigurationen, grundsätzlich aus Export- Konfigurationsgruppen und Konfigurationsgruppen-Zuordnungen. Alle erforderlichen Konfigurationseinträge können bequem über das ThemiSync Konfigurationstool verwaltet werden. Folgendes Datenmodell Konfigurationsstruktur: (Abbildung 38) zeigt den Aufbau der Benutzerhandbuch 107 Abbildung 38: Datenmodell ThemiSync Konfiguration 27.1 Exportkonfiguration (ExportConfigurationEntity) Eine Instanz des Typs ExportConfigurationEntity stellt eine atomare Einheit eines Exportvorgangs dar. Sie ist genau einem Entitätstyp zugeordnet (siehe 27.5) und muss einer Konfigurationsgruppe (siehe 27.3) angehören. Folgende Auflistung erklärt die Bedeutung der einzustellenden Parameter einer Exportkonfiguration: Property Entity Type (Entitätstyp) Beschreibung Die Zuweisung des Entitätstyps entscheidet für welche Klasse die Konfiguration bestimmt ist. ThemiSyncintern erfolgt damit die eindeutige Zuordnung von Einträgen des Änderungs- beziehungsweise Löschungsprotokolls an einen Applikationsdatentyp. Weiters bestimmt der Abarbeitungsreihenfolge Entitätstyp beim über Einfügen die der Synchronisationsdaten in die Datenbank. use Tombstone Für eine vollständige Synchronisation muss dieses Flag aktiv sein, Informationen da im deaktivierten Zustand keine über protokollierte Löschvorgänge exportiert werden und somit auf der Empfängerseite alle Daten erhalten bleiben. Bei Einwegsynchronisationen kann es durchaus sinnvoll sein „use Tombstone“ auf Benutzerhandbuch 108 False zu setzen. Config Group Eindeutige Zuordnung zu einer Konfigurationsgruppe (siehe 27.3) Description Bietet Platz für eine Beschreibung der Exportkonfiguration (für die Synchronisation nicht relevant) Join Statement Dieser optionale Parameter ermöglicht das Joinen von Datenbanktabellen für die Export-Datenselektion. Er beinhaltet SQL-Code und bietet die Möglichkeit zur Verwendung von NVelocity-Variablen an (siehe 27.6). Dabei ist zu beachten, dass auf alle Datenbanktabellen einer Klassenhierarchie Statement zugegriffen ohne zusätzliches werden kann. JoinWeitere Informationen dazu entnehmen Sie bitte der IBOFDokumentation (IFinder) Where Clause Mit der Where Clause ist es möglich, die zu exportierenden Daten einzuschränken, wobei auf alle Tabellen der zur Klasse gehörenden, deren generalisierten Klassen-Tabellen und den zusätzlich gejointen Datenbanktabellen zugegriffen werden kann. Der Parameter enthält SQL-Code und bietet die Möglichkeit zur Verwendung von NVelocity-Variablen an (siehe 27.6). Weitere Informationen dazu entnehmen Sie bitte der IBOF-Dokumentation (IFinder) 27.2 Importkonfiguration (ImportConfigurationEntity) Instanzen des Typs ImportConfigurationEntity stellen atomare Einheiten eines Importvorgangs dar. Sie sind genau einem Entitätstyp zugeordnet (siehe 27.5) und müssen einer Konfigurationsgruppe (siehe 27.3) angehören. Benutzerhandbuch 109 Folgende Auflistung erklärt die Bedeutung der einzustellenden Parameter einer Importkonfiguration: Property Beschreibung Entity Type (Entitätstyp) siehe 27.1 use Tombstone siehe 27.1 Config Group siehe 27.1 Description siehe 27.1 Preimport Rule Dieser Parameter entscheidet darüber, was vor dem Importieren mit den zum Entitätstyp passenden Daten passieren soll (betrifft die gesamte Tabelle) Optionen: Import Rule - Nothing: keine Aktion - Delete: alle Daten der Tabelle werden gelöscht Dieser Parameter entscheidet darüber, wie mit Konflikten verfahren wird. Optionen: - Overwrite: Die Daten der Empfängerseite werden überschrieben. - KeepExisting: Die Daten der Empfängerseite bleiben bestehen. - ApplicationDefined: Die Entscheidung ob die Daten überschrieben werden oder erhalten bleiben, liegt an der Applikation. Join Statement siehe 27.1 Benutzerhandbuch 110 Where Clause 27.3 siehe 27.1 Konfigurationsgruppe (ConfigurationGroupEntity) In einer Konfigurationsgruppe können mehrere Konfigurationen zusammengefasst werden. Aus jeder Konfigurationsgruppe entsteht beim Exportvorgang eine Transportdatenbank, welche alle selektierten Daten aller enthaltenen Konfigurationen enthält. Beim Importvorgang entscheiden die Einträge in der ConfigurationGroupMapping-Tabelle, (siehe 27.5) welche Importkonfigurationen/Transportdatenbanken importiert werden sollen. 27.4 Konfigurationsgruppen-Zuordnung (ConfigurationGroupMappingEntity) Die Konfigurationsgruppen-Zuordnung greift beim Importieren und entscheidet darüber, welche Exportkonfigurationsgruppen zu einer Importkonfigurationsgruppe gehören. So könnte zum „ImportPersonsConfigGroup“ Beispiel für die die Importkonfigurationsgruppe Exportkonfigurationsgruppen „ExportAthleteConfigGroup“ und „ExportTrainerConfigGroup“ verwendet werden. 27.5 Entitätstyp (EntityTypeEntity) Ein Entitätstyp ist die Darstellung von Applikationsklassen in Form von Objektinstanzen der Klasse EntityTypeEntity. Entitätstypen bieten ThemiSync die Möglichkeit einfach auf diverse Klasseninformationen (Name, Namespace) zugreifen zu können und entscheidet beim Importvorgang über die Property ResolutionSequenceNumber in welcher Reihenfolge die Importkonfigurationen abgearbeitet werden. Diese eindeutige Reihenfolge ist nötig, um beim Einfügen der Daten Konflikte mit Foreign Key Constraints in der Datenbank zu vermeiden. Die statischen Methode ThemiSyncConfig.Initialize(Database, List<IBusinessObjectDAC>) erstellt fehlende Entitätstypen und berechnet deren Sequenznummer automatisch, falls der Eintrag „CleanEntityTypes“ in der Tabelle SystemInfo mit „True“ belegt ist. Gibt es also Änderungen an der Datenstruktur einer bereits konfigurierten Benutzerhandbuch 111 ThemiSync-erweiterten Applikation, so muss dieser Eintrag der SystemInfo-Tabelle einmalig manuell auf „True“ (string) gesetzt werden. 27.6 Beispielapplikation – ThemiSync Konfiguration Als praktisches Beispiel werden nun die ThemiSync Konfigurationen zweier Synchronisationsszenarien detailliert beschrieben. Bevor nun Export- oder Importkonfigurationen angelegt werden können, muss dafür gesorgt werden, dass die Tabelle EntityType befüllt ist. Dafür wird in der Beispielapplikation (nachdem das IBOF-DB-Environment initialisiert wurde) die statische Methode ThemiSyncConfig.Initialize(Database, List<IBusinessObjectDAC>) mit folgenden Parameterwerten aufgerufen: GlobalDBEnvironment.Instance.Database, DatabaseManager.Instance.GetAllRegisteredDACClasses() Danach befindet sich für jede der vier Klassen ein Eintrag in der Tabelle und es kann mit der Erstellung der Konfigurationseinträge begonnen werden. 27.6.1 Szenario 1 Beschreibung: Im Szenario 1 sollen alle Personen (Trainer, Athleten, Benutzer) der Applikation synchronisiert werden. Konfigurationsgruppen Für die vollständige Synchronisation aller Personen würden grundsätzlich zwei Konfigurationsgruppen ausreichen. Um aber flexibel zu bleiben, werden wir für TrainerEntity, AhtleteEntity Konfigurationsgruppe und erstellen, Synchronisationsszenarien Folgende vier welche TrainerExportConfigGroup dann jeweils werden eine separat verwendet Konfigurationsgruppen Configurationtool erstellt: - UserEntity eigene auch werden also über für Exportandere können. das ThemiSync Benutzerhandbuch 112 - AthleteExportConfigGroup - UserExportConifgGroup - PersonsImportConfigGroup Konfigurationsgruppen-Zuweisungen Da beim Importieren alle drei Exportkonfigurationsgruppen verwendet werden sollen, werden nun drei Configuration Group Mapping – Einträge erstellt: - TrainerExportConfigGroup PersonsImportConfigGroup - AthleteExportConfigGroup PersonsImportConfigGroup - UserExportConifgGroup PersonsImportConfigGroup Exportkonfigurationen Da jede Exportkonfigurationsgruppe nur eine Klasse betrifft, befindet sich auch nur eine Exportkonfiguration darin. Folgende Tabellen zeigen die benötigen Konfigurationen für das Szenario 1: TrainerEntity Entity Type TrainerEntity Die zu exportierende Klasse. use Tobstone True Gelöschte Einträge sollen bei der Synchronisation berücksichtigt werden. Config Group TrainerExportConfigGroup Konfigurationsgruppe. Description Export aller Trainer Beliebiger Beschreibungstext. Join Statement Es wird keine weitere Tabelle (außer Trainer und User) benötigt, deshalb kann dieser Benutzerhandbuch 113 Parameter leer bleiben. Da alle Einträge der Tabelle Where Clause Trainer exportiert werden sollen kann dieser Parameter leer bleiben. AthletEntity Entity Type AthletEntity siehe TrainerEntity use Tobstone True siehe TrainerEntity Config Group AthleteExportConfigGroup siehe TrainerEntity Description Export aller Athleten siehe TrainerEntity Join Statement siehe TrainerEntity Where Clause siehe TrainerEntity UserEntity Entity Type UserEntity siehe TrainerEntity use Tobstone True siehe TrainerEntity Config Group AthleteExportConfigGroup siehe TrainerEntity Description Export aller Athleten siehe TrainerEntity Join Statement Where Clause siehe TrainerEntity UserID not in (SELECT Da in der Tabelle User nicht TrainerID FROM Trainer direkt festgestellt werden kann, Benutzerhandbuch 114 UNION SELECT AthletID ob es in der Tabelle Trainer FROM Athlet) beziehungsweise Athlet eine „Spezialisierung“ dazu gibt, müssen die entsprechenden Datensätze händisch ausgenommen werden. Importkonfiguration Die Konfigurationsgruppe „PersonsImportConfigGroup“ soll auf alle Exportkonfigurationen reagieren und enthält deshalb für jeden konfigurierten EntityType eine Importkonfiguration mit folgenden Werten: TrainerEntity, AthleteEntity, UserEntity Entity Type TrainerEntity, siehe Export TrainerEntity AthleteEntity, UserEntity use Tobstone True siehe Export TrainerEntity Config Group PersonsImportConfigGroup siehe Export TrainerEntity Preimport Rule Nothing Keine Aktion auf die gesamte Tabelle vor dem Importvorgang. Import Rule ApplicationDefined Bei Konflikten entscheidet die Applikation wer gewinnt. Description Import aller Trainer, siehe Export TrainerEntity Athleten, User Join Statement siehe Export TrainerEntity Where Clause siehe Export TrainerEntity Damit ist die ThemiSync-Konfiguration für das Szenario 1 abgeschlossen. Benutzerhandbuch 27.6.2 115 Szenario 2 Beschreibung: Beim Szenario 2 soll der aktuell angemeldete Trainer exportiert werden. Hier soll der Einsatz von NVelocity für die Datenselektion veranschaulicht werden. Annahme: Vor der applikationsseitigen Ausführung der Methode ThemiSyncExport.Start(); wurde über den Methodenaufruf themiSyncExport.GlobalVelocityManager.RegisterVelocityVariable(…); die NVelocity-Variable CurrentTrainer registriert, welche den aktuell am System angemeldeten Trainer (Typ: TrainerEntity) zurückgibt (siehe 28.1.1). Konfiguration Es wird eine Exportkonfigurationsgruppe und eine Exportkonfiguration (für Entität TrainerEntity) erstellt (siehe Szenario 1). Das entscheidende Merkmal in diesem Fall findet man in der Property Where Clause der Exportkonfiguration, welche auf die registrierte NVelocity-Variable zugreifen kann und somit die SQL Abfrage zur Laufzeit dynamisch erzeugt. TrainerEntity 28 … … Where Clause TrainerID = $CurrentTrainer.TrainerID … … API-Schnittstellen Alle Methoden und Properties welche vom Programmierer beim Einsatz von ThemiSync verwendet werden können, befinden sich im Namespace InfPro.ThemiSync. Die Klassenhierarchie dieser Library ist in Abbildung 39 dargestellt. Benutzerhandbuch 116 Abbildung 39: Datenmodell Infpro.ThemiSync Nachfolgend werden alle enthaltenen Klassen und deren Funktionalität detailliert beschrieben. 28.1 ThemiSyncBase ThemiSyncBase ist die Basisklasse der Typen ThemiSyncExport und ThemiSyncImport. Sie muss nie direkt instanziert werden, da sie ihre Properties und Methoden auch den abgeleiteten Klassen zur Verfügung stellt. Die Property public VelocityManager GlobalVelocityManager liefert den Globalen VelocityManager (siehe VelocityManager28.1.1), welcher das Konfigurationsgruppen-übergreifende Registrieren von Velocity-Variablen ermöglicht. Die Methode public VelocityManager GetConfigurationGroupVelocityManager(ConfigurationGroupEntity) liefert den Konfigurationsgruppen-spezifischen VelocityManager. Dieser erlaubt das Registrieren von Velocity-Variablen welche beim Synchronisationsvorgang nur der betreffenden Konfigurationsgruppe zur Verfügung stehen. 28.1.1 VelocityManager Die Klasse VelocityManager befindet sich im Namespace InfPro.ThemiSync.Utils.Velocity und bietet die Möglichkeit NVelocity- Benutzerhandbuch 117 Variablen zu registrieren und Strings unter Verwendung der registrierten Variablen auszuwerten. Die Registrierung von NVelocity-Variablen erfolgt über folgende Methode: public void RegisterVelocityVariable(string velocityName, VelocityCallback dlgt) Beim Auswerten über public string Evaluate(string templateString) werden beim Zugriff auf NVelocity-Variablen (velocityName) die entsprechenden Delegate-Methoden (dlgt) ausgeführt. 28.2 ThemiSyncConfig Die Klasse ThemiSyncConfig bietet die Methode public static void Initialize (Database database, List<IBusinessObjectDAC> iBusinessObjectDACLst) welche bei jedem Applikationsstart einmalig ausgeführt werden muss. Dabei wird die aktuelle Datenbank (z.B. GlobalDBEnvironment.Instance.Database) und eine Liste aller DACKlassen der ThemiSync-erweiterten IBOF Applikation übergeben (DatabaseManager.Instance.GetAllRegisteredDACClasses()). Zur Laufzeit kann über die Property public static bool IsInitialized überprüft werden, ob Initialize() bereits ausgeführt wurde. 28.3 ThemiSyncExport Um einen Exportvorgang umsetzen zu können, muss eine Instanz der Klasse ThemiSyncExport erstellt werden. Dem Konstruktor dieser Klasse kann eine SourceDatabase (Database-Instanz) und ein ExportPath (string) übergeben werden. Die Standardwerte (falls sie dem Konstruktor nicht übergeben werden) dieser Properties sind: Benutzerhandbuch 118 ExportPath: Path.GetTempFileName()+DBArchive.GetArchiveFileExtension() SourceDatabase: GlobalDBEnvironment.Instance.Database Die Property public List<ConfigurationGroupEntity> ConfigurationGroups liefert die Liste der zu exportierenden Konfigurationsgruppen (siehe 27.3). Wird als Transportdatenbank ein File-Basiertes Datenbanksystem verwendet, so muss der Pfad zur Vorlagedatenbank in der Property public string TemplateDatabasePath gespeichert werden. Die Vorlagedatenbank muss exakt dieselbe Datenstruktur besitzen, wie die Quell-Datenbank und darf keine Foreign Key Contstraints enthalten. Die Methode public void Start() stößt den Exportvorgang endgültig an. ThemiSyncExport bietet zur Information über den aktuellen Fortschritt während eines Exportvorganges das Event public event EventHandler<ExportProgressChangedEventArgs> ExportProgressChanged an. 28.4 ThemiSyncImport Jeder Importvorgang basiert auf einer Instanz der Klasse ThemiSyncImport. Der Konstruktor dieser Klasse benötigt mindestens den Pfad zum Transportcontainer und kann optional auch mit der DestinationDatabase (Database-Instanz) initialisiert werden. Wird die DestinationDatabase nicht übergeben, so wird standardmäßig GlobalDBEnvironment.Instance.Database verwendet. Benutzerhandbuch 119 Über die Property public IComparer<ImportConfigurationEntity> ImportConfigurationEntityComparer kann die automatisch berechnete Abarbeitungsreihenfolge der Importkonfigurationen von der Applikation aus geändert werden. Die überladenen Methoden public ImportHandler GetImportHandler(EntityTypeEntity entityType) public ImportHandler GetImportHandler(short entityTypeID) liefern einen ImportHandler für den übergebenen EntityType. Ein ImportHandler ermöglicht das Bearbeiten von importierenden Objektinstanzen vor und nach dem Synchronisationsvorgang. Damit sind sehr viele Spezialfälle – wie zum Beispiel die Synchronisation von rekursiven Strukturen – realisierbar. Bei einer Rekursion würde man beispielsweise beim ImportHandler.PreImport-Event die referenzierten untergeordneten Objekte aushängen, indem man die ID im Foreign Key Feld entfernt. Diese IDs merkt man sich Applikationsseitig und fügt sie beim ImportHandler.PostImport-Event wieder ein. Die Methode public void Start() stößt den Importvorgang endgültig an. Wurde bei einer Importkonfiguration die Import Rule „ApplicationDefined“ gewählt, so muss für die Applikationsseitige Konfliktbehandlung das Event public event EventHandler<ConflictEventArgs> Conflict; implementiert werden. Über die Property ConflictEventArgs.Cancel kann der Import der entsprechenden Entität abgebrochen werden. ThemiSyncExport bietet zur Information über den aktuellen Fortschritt während eines Importvorgangs das Event public event EventHandler<ImportProgressChangedEventArgs> ImportProgressChanged; Benutzerhandbuch 120 an. Um vor dem Löschen einer importierenden Entität diverse Aktionen ausführen zu können, wird das Event public event EventHandler<BeforeDeleteEventArgs> BeforeDelete; verwendet. Abbildungsverzeichnis Abbildung 1: Ablauf allgemeiner Synchronisationsvorgang ..................................... 16 Abbildung 2: Anwendungsfälle ................................................................................. 17 Abbildung 3: Softwareverteilung ............................................................................... 21 Abbildung 4: Systemaufbau ....................................................................................... 22 Abbildung 5: VelocityManager Zugriffsmöglichkeiten ............................................. 26 Abbildung 6: Einfaches Synchronisations-Beispiel Variante 1 ................................. 30 Abbildung 7: Einfaches Synchronisations-Beispiel Variante 2 ................................. 32 Abbildung 8: Synchronisations-Beispiel mit Konflikten ........................................... 34 Abbildung 9: Synchronisations-Beispiel mit mehreren Teilnehmern ........................ 36 Abbildung 10: Komponentenarchitektur Überblick................................................... 40 Abbildung 11: Package ThemiSync Übersicht .......................................................... 41 Abbildung 12: Datenmodell Grundstruktur ............................................................... 43 Abbildung 13: Diverse Klassen ................................................................................. 45 Abbildung 14: Datenmodell Synchronization ............................................................ 46 Abbildung 15: Datenmodell Utils .............................................................................. 47 Abbildung 16: Datenmodell Exceptions .................................................................... 48 Abbildung 17: Configuration Klassenhierarchie - vereinfachte Darstellung ............. 49 Abbildung 18: Konfigurationsgruppen - vereinfachte Darstellung ........................... 51 Abbildung 19: Ablauf Exportvorgang ....................................................................... 52 Abbildung 20: Objekthierarchie ................................................................................. 54 Abbildung 21: Klassendiagramm Initialisierung ....................................................... 56 Abbildungsverzeichnis Abbildung 22: 122 Sequenzdiagramm zum Visualisieren eines vollständigen Initialisierungsvorgangs ............................................................................................. 57 Abbildung 23: Datenmodell Metadaten-spezifische Klassen .................................... 61 Abbildung 24: Konfiguration Technisches Klassendiagramm .................................. 68 Abbildung 25: Beispiel für ein ExportConfigurationEntity Objekt ........................... 72 Abbildung 26: Beispiel für ein VelocityManager Objekt .......................................... 72 Abbildung 27: Klassendiagramm Export ................................................................... 73 Abbildung 28: Datenmodell Transport-Container ..................................................... 77 Abbildung 29: Sequenzdiagramm zum Visualisieren des Exportvorgangs (Querformat) .............................................................................................................. 78 Abbildung 30: Klassendiagramm Import ................................................................... 79 Abbildung 31: Sequenzdiagramm zum Visualisieren des Importvorgangs (Querformat) .............................................................................................................. 83 Abbildung 32: Projektphasen Qualitätsmanagement ................................................. 92 Abbildung 33: Beispielapplikation UML Diagramm ................................................ 98 Abbildung 34: ThemiSync Configurationtool ......................................................... 100 Abbildung 35: ThemiSync Datenbanktabellen Übersicht ........................................ 101 Abbildung 36: Beispielapplikation Tabellen ........................................................... 103 Abbildung 37: IBOF Generator ............................................................................... 104 Abbildung 38: Datenmodell ThemiSync Konfiguration .......................................... 107 Abbildung 39: Datenmodell Infpro.ThemiSync ...................................................... 116 Literaturverzeichnis [San 09] S. Sanderson, Pro ASP.NET MVC Framework, 1. Auflage, Apress Verlag, USA, 2009 [KemEik 06] A. Kemper/A.Eickler, Datenbanksysteme – Eine Einführung, 6. Auflage, Oldenbourg Wissenschaftsverlag GmbH, München, 2006 [Tro 07] A. Troelsen, Pro C# 2008 and the .NET 3.5 platform, 4. Auflage, Apress Verlag, USA 2007