LotusScript-Dokumentvergleich

15.10.2006 von Elmar Fuchs
Durch die Bearbeitung eines Dokuments von zwei oder mehreren Benutzern in unterschiedlichen Repliken einer Datenbank entstehen Replizierkonflikte. Die notwendige manuelle Auswertung der Konfliktdokumente lässt sich mittels eines LotusScript-Agenten vereinfachen.

Die Möglichkeit der verteilten Anwendung mehrerer Repliken einer Datenbank über verschiedene Server und gegebenenfalls auch lokale Workstations ist eine der zentralen Komponenten von Lotus Notes/Domino. Bearbeiten und speichern dabei zwei oder mehrere Benutzer dasselbe Dokument, kommt es bei einer nachfolgenden Replikation zu einem Replizierkonflikt (Bild 1).

Bild 1: Dokumente, bei denen ein Replizier- oder Speicherungskonflikt erkannt wurde.

Im Zusammenhang mit Replizierkonflikten werden häufig die Speicherkonflikte genannt. Diese entstehen, wenn zwei oder mehrere Benutzer dasselbe Dokument in derselben Replik bearbeiten und anschließend speichern. Der folgende Artikel beschäftigt sich ausschließlich mit Replizierkonflikten.

Replizierkonflikte

Stellt Notes Domino bei der Replizierung fest, dass bei einem Dokument ein Replizierkonflikt vorliegt, wird ein Dokument zum Hauptdokument und die weiteren Dokumente zu Antwortdokumenten. Welches Dokument dabei als Hauptdokument festgesetzt wird, hängt von zwei Faktoren ab:

Besondere Beachtung finden gelöschte Dokumente. Wird ein Dokument in einer Replik entfernt, nachdem es in einer anderen bearbeitet und gespeichert wurde, greift das Löschen. Wurde das Dokument jedoch mehrfach bearbeitet oder die Löschung ausgeführt, bevor die Bearbeitung in der anderen Replik stattfand, bleibt es erhalten, da diese Situationen Vorrang vor dem Löschen haben.

Welche Konsequenzen hat nun die Erstellung der Konfliktdokumente? Für das als Hauptdokument gesetzte Dokument gar keine. Es ist ein normales Dokument, das die gespeicherten Änderungen enthält. Für die Antwortdokumente sieht das anders aus. Erstens werden diese optisch über eine Raute in der Ansicht (Bild 1) gekennzeichnet, zweitens enthält dieses Dokument drei zusätzliche Felder:

Replizierkonflikte vermeiden

Zur Vermeidung von Replizierkonflikten stehen Ihnen verschiedene Methoden zur Auswahl. Eine Maßnahme, die generell für jede Datenbank empfehlenswert ist, ist die Einschränkung der Benutzerrechte in der Datenbank auf das Zugriffslevel Author und die Verwendung von Autorenfeldern in den Dokumenten. Damit können Sie verhindern, dass Benutzer Dokumente anderer Benutzer bearbeiten.

Des Weiteren lassen sich durch die Einrichtung der seit Version 6 möglichen Sperrung von Dokumenten ebenfalls Replizierkonflikte vermeiden. Aus Entwicklersicht hat man zwei Optionen:

Tabelle 1: Die möglichen Einstellungen für die Felder zur Versionskontrolle

Feld_Wert

Wirkung

Versioning

New versions
become responses

Das Originaldokument steht in der Ansicht an der Spitze der Hierarchie. Bearbeitete Versionen werden als Antwortdokumente untergeordnet. Mit dieser Einstellung vermeiden Sie Replizierkonflikte.

Prior versions
become responses

Bei dieser Einstellung steht immer die zuletzt gespeicherte Version ganz oben, das ältere Dokument wird untergeordnet. Damit können wiederum Replizierkonflikte auftreten.

New versions
become siblings

Mit diesem Eintrag werden ebenfalls become siblings Replizierkonflikte konsequent verhindert. Bei jeder Bearbeitung und Speicherung eines Dokuments wird ein neues Dokument erstellt. Es gibt nur Haupt- und keine Antwortdokumente.

Create versions

Manual/File,
New Version

Bei Auswahl dieser Einstellung überlassen Sie dem Benutzer ob beim Speichern eines bearbeiteten Dokuments ein neues Dokument erstellt wird. Damit können wiederum Replizierkonflikte auftreten.

Atomatic/File, Save

Durch diesen Eintrag erzwingen Sie die Erstellung neuer Dokumente. Replizierkonflikte können so in Verbindung verhindert werden.

Tabelle 2: Die Bedeutung der Werte des Feldes $VersionOpt

Wert des Feldes $VersionOpt

Entspricht den Eigenschaften

0

Nicht gesetzt, keine Versionskontrolle

1

New versions become responses und
Manual/File, New Version

2

New versions become responses und
Automatic/File, Save

3

Prior versions become responses und
Manual/File, New Version

4

Prior versions become responses und
Automatic/File, Save

5

New versions become siblings und
Manual/File, New Version

6

New versions become siblings und
Automatic/File, Save

Bild 2: Die Einstellungen zur Behandlung von Replikationskonflikten.

Das Mischen der Werte in einem Dokument kann von Vorteil sein, birgt jedoch auch das Risiko, dass so genannte Geisterdokumente entstehen. Wird zum Beispiel in einer Replik von einer Person der Name, in der anderen Replik jedoch die Adresse geändert, ist nach der Replizierung ein Personeneintrag mit einem neuen Namen und der neuen Adresse vorhanden, den es so in der Realität nicht gibt.

Konfliktdokumente auswerten

Sind Replizierkonflikte in einer Datenbank entstanden, müssen sie ausgewertet und die betreffenden Dokumente konsolidiert werden. Dies sollte möglichst zeitnah zu ihrer Entstehung erfolgen, um sicherzustellen, dass die Benutzer der Datenbank mit den korrekten Daten arbeiten. Außerdem vergrößert sich mit möglichen weiteren Änderungen an den verschiedenen Dokumenten der Aufwand zur Behebung des Konflikts.

Um die Daten wieder in einem korrekten Dokument abzuspeichern, müssen Sie die Wertinhalte des Haupt- und des Antwortdokuments vergleichen. Öffnen Sie anschließend beide Dokumente im Bearbeitungsmodus, und kopieren Sie die aktuelleren Werte aus dem Dokument, das Sie löschen wollen, in dasjenige, welches Sie behalten wollen. Speichern Sie anschließend das aktualisierte Dokument, und löschen Sie das andere. Wenn Sie das Antwortdokument aktualisieren, wird es mit dem Speichern automatisch zum Hauptdokument.

Unterstützung mit LotusScript

Der Vergleich von Dokumenten und dem Inhalt der einzelnen Felder von Hand ist sehr aufwendig. Mit Hilfe eines LotusScript-Agenten kann dies automatisch erfolgen und so die Arbeit wesentlich erleichtern. Der im Folgenden vorgestellte Agent (Listing 1) vergleicht zwei in einer Ansicht ausgewählte Dokumente und sendet die Auswertung per Mail an den aktuell angemeldeten Benutzer. Dabei werden folgende Unterschiede aufgezeigt:

Sub Initialize
Dim se As New NotesSession
Dim db As NotesDatabase
Dim col As NotesDocumentCollection
Dim doc1 As NotesDocument
Dim doc2 As NotesDocument
Dim mailDoc As NotesDocument
Dim ausgabe1 As String
Dim ausgabe2 As String
Dim ausgabe3 As String
Dim ausgabe4 As String
Dim fehler As Boolean
Dim f1 As Variant
Dim f2 As Variant
Dim i As Integer
Dim rtItem As NotesRichTextItem
fehler = False
ausgabe1 = ""
ausgabe2 = ""
ausgabe3 = ""
ausgabe4 = ""
Set db = se.CurrentDatabase
Set col = db.UnprocessedDocuments [1]
If col.Count <> 2 Then [2]
Msgbox "Um einen Vergleich auszuführen müssen Sie zwei Dokumente auswählen!", _
48, "Fehler bei Dokumentauswahl"
Exit Sub
End If
Set doc1 = col.GetFirstDocument [3]
Set doc2 = col.GetLastDocument [3]
Forall k In doc1.Items [4]
If doc2.HasItem(k.Name) Then [5]
f1 = k.values
f2 = doc2.GetItemValue(k.Name)
If Ubound(f1) <> Ubound(f2) Then [6]
fehler = True
ausgabe1 = ausgabe1 + "Feldname: '"+ k.Name + Chr(13)
ausgabe1 = ausgabe1 + "Feldwerte in Dokument1: " + _
Cstr(Implode(k.values," - ")) + Chr(13)
ausgabe1 = ausgabe1 + "Feldwerte in Dokument2: " + _
Cstr(Implode(doc2.GetItemValue(k.Name)," - ")) + Chr(13) + Chr(13)
Else [7]
For i = 0 To Ubound(f1)
If f1(i) <> f2(i) Then
fehler = True
ausgabe2 = ausgabe2 + "Feldname: "+ k.Name + Chr(13)
ausgabe2 = ausgabe2 + "Feldwerte in Dokument1: " + _
Cstr(Implode(k.values," - ")) + Chr(13)
ausgabe2 = ausgabe2 + "Feldwerte in Dokument2: " + _
Cstr(Implode(doc2.GetItemValue(k.Name)," - ")) + Chr(13) + Chr(13)
End If
Next
End If
Else [8]
fehler = True
ausgabe3 = ausgabe3 + "Feldname: "+ k.Name + Chr(13)
ausgabe3 = ausgabe3 + "Feldwerte in Dokument1: " + _
Cstr(Implode(k.values," - ")) + Chr(13) + Chr(13)
End If
End Forall
Forall k In doc2.Items [9]
If Not doc1.HasItem(k.Name) Then
fehler = True
ausgabe4 = ausgabe4 + "Feldname: "+ k.Name + Chr(13)
ausgabe4 = ausgabe4 + "Feldwerte in Dokument2: " + _
Cstr(Implode(k.values," - ")) + Chr(13) + Chr(13)
End If
End Forall
If Not fehler Then [10]
Msgbox "Die Dokumente stimmen überein", 48, ""
Else
Set mailDoc = db.CreateDocument
mailDoc.Form = "Memo"
mailDoc.SendTo = se.UserName
mailDoc.Subject ="Auswertung des Dokumentvergleichs in der Datenbank "+ _
db.Title+", "+ db.FileName
Set rtItem = New NotesRichTextItem(mailDoc, "Body")
Call rtItem.AppendText("Auswertung des Dokumentvergleichs in der Datenbank "+ _
db.Title+", "+ db.FileName)
Call rtItem.AddNewline(1)
Call rtItem.appendText("Dok-ID Dokument 1: "+ doc1.UniversalID+ " ")
Call rtItem.AppendDocLink(doc1,"")
Call rtItem.AddNewline(1)
Call rtItem.AppendText("Dok-ID Dokument 2: "+ doc2.UniversalID+ " ")
Call rtItem.AppendDocLink(doc2,"")
Call rtItem.AddNewline(2)
Call rtItem.AppendText("Es sind folgende Unterschiede zwischen den beiden _
Dokumenten vorhanden:")
Call rtItem.AddNewline(1)
Call rtItem.AppendText("----------------------------------------------------")
If ausgabe1 <> "" Then
Call rtItem.AddNewline(2)
Call rtItem.AppendText("Die Anzahl der Feldwerte in folgenden Feldern _
stimmt nicht überein:")
Call rtItem.AddNewline(1)
Call rtItem.AppendText(ausgabe1)
End If
If ausgabe2 <> "" Then
Call rtItem.AddNewline(2)
Call rtItem.AppendText("Die Feldwerte in folgenden Feldern sind _
unterschiedlich:")
Call rtItem.AddNewline(1)
Call rtItem.AppendText(ausgabe2)
End If
If ausgabe3 <> "" Then
Call rtItem.AddNewline(2)
Call rtItem.AppendText("Fehlende Felder im zweiten gewählten Dokument:")
Call rtItem.AddNewline(1)
Call rtItem.AppendText(ausgabe3)
End If
If ausgabe4 <> "" Then
Call rtItem.AddNewline(2)
Call rtItem.AppendText("Zusätzliche Felder in zweiten gewählten Dokument:")
Call rtItem.AddNewline(1)
Call rtItem.AppendText(ausgabe4)
End If
Call mailDoc.Send(False)
End If
End Sub

Zugriff auf die Dokumente

Nach der Deklaration der benötigten Variablen und der Zuweisung einiger Startwerte erfolgt der Zugriff auf die beiden ausgewählten Dokumente über die Eigenschaft UnprocessedDocuments der aktuellen Datenbank [1]. Diese werden einem Objekt der Klasse NotesDocumentCollection zugewiesen. Im nächsten Schritt wird geprüft, ob genau zwei Dokumente ausgewählt worden sind. Dazu wird der Inhalt der Eigenschaft Count des Sammlungsobjekts ausgewertet [2]. Ist dies nicht der Fall, wird eine Meldung ausgegeben und die Agent-Ausführung beendet. Andernfalls werden die beiden Dokumente jeweils einer Objektvariablen der Klasse NotesDocument zugewiesen [3]. Nun beginnt die eigentliche Überprüfung der Dokumente. Der Reihe nach wird auf alle Felder des ersten Dokuments zugegriffen [4]. Als Erstes wird verglichen, ob das Feld im zweiten Dokument vorhanden ist [5]. Ist dies der Fall, wird die Anzahl der Werte in diesem Feld verglichen. Stimmt sie nicht überein [6], werden der Feldname sowie die aktuellen Werte in beiden Dokumenten in die Variable ausgabe1 geschrieben.Stimmt die Anzahl überein, wird geprüft, ob die Feldwerte identisch sind [7]. Ist dies nicht der Fall, werden der Feldname sowie die aktuellen Werte in beiden Dokumenten in die Variable ausgabe2 geschrieben.

Ist das Feld des ersten Dokuments nicht im zweiten enthalten, werden der Feldname und die aktuellen Werte des ersten Dokuments in der Textvariablen ausgabe3 hinterlegt [8].

Abschließend muss noch geprüft werden, ob das zweite Dokument Felder enthält, welche im ersten fehlen [9]. Informationen für entsprechende Fälle werden in der Variablen ausgabe4 gespeichert.

Unterschiede bei den Überprüfungen

Wurden bei den Überprüfungen Unterschiede festgestellt, wurde die boolesche Variable fehler auf den Wert True gesetzt. Dieser Wert wird nun überprüft [10]. Wurde kein Unterschied festgestellt, wird eine entsprechende Mitteilung ausgegeben und der Agent beendet. Andernfalls wird ein neues Dokument erstellt. In diesem werdenneben einigen textlichen Informationen die universellen Dokument-IDs der Dokumente, ein Link auf jedes Dokument sowie die in den Textvariablen gesammelten Informationen zusammengestellt. Abschließend wird das Dokument an den aktuell angemeldeten Benutzer geschickt. Dieser erhält eine E-Mail, deren prinzipieller Inhalt dem in Listing 2 dargestellten Beispiel entspricht.

Auswertung des Dokumentvergleichs in der Datenbank RepKonflikte, RepKonflikte.nsf
Dok-ID Dokument 1: 21DBE97A4DF85C45C12571AF0047C9C1 (<DocLink>)
Dok-ID Dokument 2: 21DBE97A4DF85C45C12571AF00489044 (<DocLink>)
Es sind folgende Unterschiede zwischen den beiden Dokumenten vorhanden:
----------------------------------------------------------------------------------
Die Anzahl der Feldwerte in folgenden Feldern stimmt nicht überein:
Feldname: '$UpdatedBy
Feldwerte in Dokument1: CN=Don Admin/O=efuchs - CN=Elmar Fuchs/O=efuchs
Feldwerte in Dokument2: CN=Don Admin/O=efuchs
Feldname: '$Revisions
Feldwerte in Dokument1: 18.07.2006 15:04:55 - 18.07.2006 15:05:31 - 18.07.2006 15:16:07
Feldwerte in Dokument2: 18.07.2006 15:04:55 - 18.07.2006 15:05:31
Die Feldwerte in folgenden Feldern sind unterschiedlich:
Feldname: OriginalModTime
Feldwerte in Dokument1: 18.07.2006 15:16:09
Feldwerte in Dokument2: 18.07.2006 15:15:44
Feldname: Telefon
Feldwerte in Dokument1: 0123-1234568
Feldwerte in Dokument2: 0123-1234567
Feldname: Fax
Feldwerte in Dokument1: 0123-1234568
Feldwerte in Dokument2: 0123-1234567
Zusätzliche Felder in zweiten gewählten Dokument:
Feldname: $ConflictItems
Feldwerte in Dokument2: OriginalModTime - Telefon - Fax
Feldname: $REF
Feldwerte in Dokument2: 21DBE97A4DF85C45C12571AF0047C9C1
Feldname: $Conflict
Feldwerte in Dokument2:

Zusammenfassung

Lassen sich Replizierkonflikte nicht vermeiden, wird die Analyse und die Konsolidierung der Dokumente zu einer wichtigen Aufgabe des Datenbankadministrators. Mit Hilfe eines LotusScript- Agenten können Sie sich die Arbeit des Dokumentvergleichs erleichtern.