Transformation der Ordnerstrukturen von 3.3 nach 4.0

Dieser Artikel gibt einen kurzen Überblick über das Konzept der Ordnerstrukturen in 4.0 sowie das Vorgehen bei der Transformation der Strukturen von 3.3 nach 4.0.

Kurzeinführung

Motivation

Die Änderung des Konzepts zur Strukturierung von Objekten ist durch zwei wesentliche Aspekte motiviert: Performance und Flexibilität. Das bisherige Design konnte zu starken Performance-Einbußen führen, wenn Objekte an mehreren Ablageorten mit unterschiedlichen Berechtigungen gespeichert wurden. Darüber hinaus mussten neue Objekte angelegt werden, wenn die Ordnungsstruktur je nach Sachgebiet anders dargestellt werden sollte. Die neuen Ordnerstrukturen auf Basis von Strukturelementen, die Suchbedingungen darstellen, bieten hier deutliche Vorteile.

Wer Zeit hat, der mag sich die folgende Präsentation zu den neuen Ordnerstrukturen (vormals 'virtuelle Ordner') anschauen. Sie steht hier zur Verfügung:

Unterschied zwischen Nutzung von Unterordnern in 3.3 und der Konfiguration von Ordnungsstrukturen in 4.0.

Werden statische Strukturen über die Ablage von Objekten vom Typ (Unter)Ordner in einen Kontextordner oder Ordner gebildet, so erfolgt dies im Fall der neuen Ordnerstrukturen durch die Konfiguration von Strukturelementen, die eine Suche auf Indexdaten von Objekten des Typs Dokument darstellen. D.h. in Zukunft wird auf Objekte vom Typ (Unter)Ordner komplett verzichtet. Die alten Kontextordner dagegen werden beibehalten, heißen nun aber Ordner. Sie bilden die Klammer um eine Akte und steuern so u.a. allgemeine Zugriffsrechte und Aufbewahrungsregeln für alle in ihm abgelegten Objekte. Die strukturierenden Daten sind direkt am Dokumentobjekt definiert. Durch entsprechende Eingaben ordnen sich die Objekte automatisch dort ein, wo sie laut Konfiguration vorgesehen sind.

Visualisierung im Client

Visuell erscheinen dem Anwender die neuen Ordnungsstrukturen sehr ähnlich wie zuvor. Es gibt nun aber deutlich mehr Möglichkeiten der Gruppierung von Objekten, aber auch der Bildung von Summen, wie z.B. dem Wert von Rechnungen nach Monat oder genommener Urlaub im Jahr. Siehe weitere Details hier.

Änderungen im Schema

Es gibt weiterhin nur einen Kontextordner pro Objekttypgruppe. Dagegen entfällt das Anlegen weiterer Objekttypen vom Typ Ordner.

Die Konfiguration der neuen Ordnerstrukturen wird am (Kontext)Ordner in der Facette 'Ordnerstruktur' hinterlegt. Welche Möglichkeiten der Konfiguration zur Verfügung stehen, siehe dazu hier.

Es gibt einen neuen Service, der den Client mit der Ordnungsstruktur versorgt: Structure Service.

Änderung für Ablageorte

Ein Objekt kann nur noch an einem Ablageort abgelegt werden. Der Client 3.3 hatte dies schon berücksichtigt. Nun ist auch per API eine weitere Ablage an einem anderen Ort nicht mehr möglich.

Sollen Objekte an einem anderen Ablageort sichtbar gemacht werden, kann diese entweder durch Nutzung von Mehrfachfeldern, die zur Strukturbildung beitragen, durch Referenzfelder oder durch das Erstellen von Verweisdokumenten erfolgen.

Teilakten

Die statischen Strukturen ermöglichten die Verschachtelung von Teilakten, d.h. von Ordnertypen mit diese Akten auszeichnenden weiteren Indexfeldern. Das Alternativkonzept hierzu ist zukünftig die Nutzung von Referenzfeldern und die Anzeige referenzierter Objekte auch im Strukturbaum. Diese Funktion wird im Laufe der nächsten Entwicklungsschritte der Version 4.x zur Verfügung gestellt. Aktuell sind die Referenzen in den Aspekten der Kontextordner erreichbar.

Transformation

Im Folgenden wird das Vorgehen für die Transformation der Strukturen beschrieben.

Zur Unterstützung der Transformation stehen Template-Skripte zur Verfügung, die entsprechend der zuerst durchzuführenden Analyse auf die vorhandenen Quell- und die gewünschten Zielstrukturen angepasst werden müssen. Diese nutzen neue REST-API Endpunkte für Batch-Operationen für eine performante Verarbeitung der Transformation.

Schritte für die Transformation

Die folgenden Schritte sind für die Durchführung der Transformation zu durchlaufen:

  • Schritt 0: Update auf den letzten Release Candidate der Version 3.3

Ist noch nicht das letzte freigegebene Inkrement von Version 3.3 installiert, muss zuerst eine Aktualisierung auf diese Version erfolgen: 2018-04-25 
Hier ist wie immer zu beachten, welche weiteren Update-Schritte in den einzelnen Digests aller Releases, die ggf. übersprungen werden, notwendig sind.

  • Schritt 1. Analyse der Szenarien und Konzept für die Transformation

Unterordner und Standorte werden nun virtuell durch die Auszeichnung in Indexdatenfeldern dargestellt und ersetzt.
Es ist daher zu klären, um welche Indexdatenfelder die vorhandenen Objekte erweitert werden müssen und mit welchen Informationen diese befüllt werden müssen um die bisher in der Standortrelation und den Eltern-Objekten festgehalten Informationen zu ersetzen.

Gab es bisher eine feste Menge an Unterordern die immer vorhanden waren - z.B. Dokumente, Fotos, E-Mails, so kann dies beispielsweise durch ein neues Katalogfeld "Dokumenttyp" mit den möglichen Katalogwert "Dokument", "Foto" und "E-Mail" ersetzt werden. Der Structure Service kann dann auf dieses Feld als Strukturelement konfiguriert werden und im Client stehen die 3 Werte des Katalogs als virtuelle Ordner zur Verfügung.

  • Schritt 2: Schema anpassen

Auf Basis des Konzepts sind die Datenstrukturen passend zu erweitern. D.h. es sind die folgenden Punkte zu berücksichtigen:

    • Dokumenttypen sind um entsprechende Indexdatenfelder zu erweitern.
    • Es sind ggf. passende Kataloge anzulegen.
    • Die Standortrelationen aller Dokumenttypen müssen die Anlage von Instanzen des Dokumenttyps im Kontextordner erlauben.
    • Die Formulare der Dokumenttypen sind ggf. um die neuen Felder zu ergänzen.
    • Skripte sind ggf. entsprechend anzupassen.
    • Für jeden Kontextordner ist eine passende Strukturelemente Definition zu hinterlegen. Siehe dazu auch die Folder Structure API.

Achtung: 

Wenn es im Schema Ordnertypen gibt, die bisher keine Kontextordner waren aber für Version 4.0 zu einem Kontextordner gemacht werden und von denen bereits Instanzen in enaio existieren, dann müssen die Informationen der Elasticsearch-Datenbank aller vorhandenen Objekt-Instanzen die ein Kindobjekt dieser Instanzen sind durch eine Nachindizierung um die Kontextordner-Informationen ergänzt werden. Werden die Objekte im Folgenden durch neue Felder erweitert und über die Transformations-API angereichert, so geschieht dies automatisch. Ist dies nicht der Fall muss die Nachindizierung manuell angestoßen werden. Dies ist im enterprise-manager über die "Nachträgliche Volltextindizierung" Operation möglich.

  • Schritt 3: Update auf 4.0

Nachdem alle Objekttypen angepasst wurden und das Schema auf dem Server aktiviert wurde, kann das Update auf Version 4.0 durchgeführt werden.

Bitte auch die Hinweise auf notwendige manuelle Anpassungen nach der Durchführung der Aktualisierung beachten.

Achtung:

    • Nach der Aktualisierung auf Version 4.0 steht der bisherige 3.x Client nicht mehr zur Verfügung. Der nun aktuelle 4.0 Client kann keine Eltern-Kind Beziehungen (außer den virtuellen) mehr darstellen. Des Weiteren sind die virtuellen Strukturen erst nach der in Schritt 4 durchzuführenden Transformation im Client sichtbar. Wenn das zu aktualisierende System sehr viele (> 1 Mio.) DMS-Objekte enthält und eine längere Downtime nicht akzeptabel ist, sollte der Transformationsschritt 1 aus Schritt 4 vor der Aktualisierung auf Version 4.0 im laufenden Betrieb ausgeführt und erst im Anschluss eine Aktualisierung auf Version 4.0 durchgeführt werden. Alternativ und nur in Absprache mit OS kann auch der 3.x Client für einen Übergangszeitraum unter Version 4.0 betrieben werden.
    • Der enaio redline designer 4.0 wird zwar noch vorhandene Unterordner zur Konfiguration anbieten, jedoch können keine neuen Unterordner mehr angelegt werden.
  • Schritt 4: Durchführung der Transformation

Achtung: Es empfiehlt sich, die Transformation auf einem Testsystem zu validieren.

Mittels der weiter unten beschriebenen Endpunkte der Transformations-API können die in Schritt 2 neu angelegten Felder mit den entsprechenden Werten ihrer Eltern-Objekte oder mit Festwerten angereichert werden. Dies geschieht pro neuem Feld jedes Dokumenttyps einzeln. Weiterhin können die Objekte mittels der Transformations-API im Bulk verschoben und gelöscht werden. Dies wird genutzt um die Objekte von ihren derzeitigen Standorten direkt unter einen Kontextordner zu verschieben bzw. leere Unterordner zu löschen.
Da hier ggf. sehr viele Aufrufe der Transformations-API durchgeführt werden müssen, empfiehlt es sich Skripte für die Durchführung der Transformation zu erstellen. Dies ist im Abschnitt "Nutzung der Transformations-API und Erstellung von Skripten" weiter unten genauer beschrieben. Es stehen auch Templates zur Verfügung.

Transformationsschritt 1: Die Dokumentobjekte werden mittels der Transformations-API und den erstellten Skripten mit den Daten der wegfallenden Unterordner und Standorte angereichert.

Transformationsschritt 2: Die Dokumentobjekte werden mittels der Transformations-API direkt unter ihren Kontextordner verschoben

Transformationsschritt 3: Die zurückgebliebenen leeren Unterordner werden mittels der Transformations-API gelöscht.

Umstellungen von Business Logik

Nach der Transformation der Objektstrukturen ist nach Bedarf die Business Logik in Skripten umzustellen. Es sind alle Stellen betroffen, die die gelöschten Unterordner behandeln. So kann z.B. das automatisierte Anlagen von Unterordnern nach der Erstellung von Kontextordnern entfernt werden. 

Artefakte, die ggf. noch von Anwendern manuell zu bereinigen sind

Nach dem Löschen der Unterordner können noch Favoriten zu diesen vorhanden sein. Diese können durch die Anwender manuell entfernt werden.

  • Schritt 5: Schema abschließend anpassen

Im Schema sind alle Ordnertypen zu entfernen, die nicht als Kontextordner weiter verwendet werden.

Ggf. ist das Rechtesystem bzgl. Rollen und Klauseln anzupassen.

Nutzung der Transformations-API und Erstellung von Skripten

Im Folgenden wird die zur Verfügung gestellte Transformations-API sowie die Erstellung von Skripten für die Transformation beschrieben

  • Transformations-API

DmsBatchService.updateObjects 

Provides batch updates of objects by query. You may modify a list of objects by providing a id list or by defining a search query. Warning: This operation may modify a large list of objects.

Example json for update by id

{ "query": { "expression" : ["ID1","ID2","ID3"], "type" : "mydocument" }, "data": { "stringstatefield": { "value" : "newvalue" }, "numbervaluefield": { "value" : 42 } } }

This example updates all objects with the given ids of the type 'mydocument' and sets the indexdata as given by the data object in the json.

The query object

The query expression supports a list of object ids or a simple query in the same syntax as ResultService.getQueryResult. The type property must be set, for the simple query and is used as type for the id list. For the id list, you may set the type to sysobject.

The data object

With the data object, one are more changes of the custom indexdata field can be described. The fields are identified by the technical name of the field. For example, if you want to change the value of the field 'name' to the fixed value 'Max', you can use this data object.

{ "data": { "name": { "value" : "Max" }, } }

The data object supports these properties

PropertyComment
valueFixed new value for the field. The value is expected in the same syntax as for any dms object. See DmsService
parentrefTechnical qualified name of a parent object field. The value of the parent object is copied to the index data field of the object. If the parent can not be found for this object, if the object is not a child of this parent type, the value will be used as fall back. If also the value was not set, a error is reported.
onlyifemptyIf set to true the index data field is only updated to a new value, if the value is currently not set. A value is not set, if the current field value is null or a empty string. The default is false.

The move operation

A move of the object is also possible, by providing a move target with the moveto.

For example this update json

{ "query": { "expression" : ["ID1","ID2","ID3"], "type" : "mydocument" }, "moveto" : "PARENTID" }

will move any object with the given id to the location given by 'PARENTID'.

Other possible move targets are the fixed root target and the context target. The context move target will move the object as direct child of the context folder. Note: This functionality will likely be removed in future versions.

The options

The options object can be used, to change the behavior of the update operation Supported properties for the options are

PropertyDefault valueComment
ignoremissingfalseIf a id list expression is used and this list contains id for objects that can not be found, this is handled as failure, only if this option is set to false. If the option is set to true, only a warning is reported.
breakonerrorfalseIf set to true, the operation will be canceled on the first failure that occurs.

Comprehensive example

The following example shows the use of a parent reference and a query that uses a parent property.

{ "query": { "expression" : "personalfile.typefield=employee;statefield=active"], "type" : "document" }, "data": { "statefield": { "value" : "inactive" }, 
"stringfield": { "parentref" : "personalfile.anotherstringfield" } }, "moveto":"context", "options": { "breakonerror" : true } }

Using this update json will lead to this result:

Every document that has the current statefield value 'active' inside a context folder with the typefield value 'employee' will get the state 'inactive' and the value of 'stringfield' will be the same as the value of 'anotherstringfield' on the context folder. If the object is located insider a subfolder, it will also be moved to the context folder. If the operation runs in an error, it will be canceled immediately.

Transactions handling and return code

Each object update is run in one transaction. If a object fails to be updated, this fail is reported as failure in the result. The other objects, that are marked as success will not be rolled back. If the operation was completely successful a ok (200) will be returned. If the operation has completely failed, if for example the input json can not be parsed, a error code like bad request (400) is returned. If the operation as partly failed a conflict (409) will be returned. In this case, the return will also contain a list of objects that have failed.


Returns
Returns a update summary as report. Set details to true to enable a report of the updated objects.

Endpoint method overview

PropertyValue
Qualified nameDmsBatchService.updateObjects
Full path/rest-ws/service/dms/batch
Success code200: OK
Failure codes400: The input json can not be parsed. See cause message for more details. [DMS_METADATA_JSON_INPUT_PARSING_ERROR]
HTTP methodPUT
Types consumedapplication/json; charset=utf-8
Types producedapplication/xml; charset=utf-8,application/json; charset=utf-8
Required privilegeNo special privileges are required to invoke this endpoint,

Endpoint request parameter

NameCommentTypeInput
detailsIf set to true, a detailed success report of the updated objects is returned.QUERYtrue false
inThe update input (JSON) as body content.CONTEXTjson-body


DmsBatchService.deleteObjects 

URIhttp://localhost:8080/rest-ws/service/dms/batch/delete

Batch deleteion of objects by query.

Example for delete by id:

{ "query": { "expression" : ["ID1","ID2","ID3"] } }

The accepted json is the same as used in the update endpoint. But moveto and data properties will be ignored. Especially the query object is described in the update operation. See DmsBatchService.updateObjects.

The options

These options object can be used, to change the behavior of the delete operation. Supported properties for the options are

PropertyDefault valueComment
harddeletefalseOnly if this property is set to true, the objects will be deleted permanently.
deleteonlyemptyfolderstrueIf set to false, even folders that still contain child objects, will be deleted or recycled. The deletion will be recursive and the child objects are also get deleted.

For other possible options see DmsBatchService.updateObjects Note:

This endpoint is using POST, because some http frameworks forbid a DELETE request with body content.

Transactions handling and return code

Each object update is run in one transaction. If a object fails to be deleted, this fail is reported as failure in the result. The other objects, that are marked as success will not be rolled back. If the operation was completely successful a ok (200) will be returned. If the operation has completely failed, if for example the input json can not be parsed, a error code like bad request (400) is returned. If the operation as partly failed a conflict (409) will be returned. In this case, the return will also contain a list of objects that have failed.


Returns
Returns a deletion summary as report. Set details to true to enable a report of the deleted objects.

Endpoint method overview

PropertyValue
Qualified nameDmsBatchService.deleteObjects
Full path/rest-ws/service/dms/batch/delete
Success code200: OK
Failure codes400: The input json can not be parsed. See cause message for more details. [DMS_METADATA_JSON_INPUT_PARSING_ERROR]
HTTP methodPOST
Types consumedapplication/json; charset=utf-8
Types producedapplication/xml; charset=utf-8,application/json; charset=utf-8
Required privilegeNo special privileges are required to invoke this endpoint,

Endpoint request parameter

NameCommentTypeInput
detailsIf set to true, a detailed success report of the deleted objects is returned.QUERYtrue false
inThe update input (JSON) as body content.CONTEXTjson-body


  • Erstellung von Skripten

    Im Folgenden sind zwei node.js Skripte "batchrunner.js" und "index.js" zu sehen. 
    Das Skript batchrunner.js ist für den Aufbau der Verbindung und die Ausführung der API-Calls verantwortlich. 

    batchrunner.js
    const request = require('request');
    const util = require('util');
    
    var host = 'http://10.10.1.512:8080';
    var auth = {
       'user': 'root',
       'pass': 'password',
       'sendImmediately': true
    }
    
    module.exports.executeUpdate = ((query) => {
    
      var options = {
        url : host + '/rest-ws/service/dms/batch',
        method: 'PUT',
        headers : {
          'accept' : 'application/json; charset=UTF-8'
        },
        auth : auth,
        json : query
      }
      console.log('Batch update service url  : '+options.url);
      console.log('Batch update service query:\n'+util.inspect(options.json, false, null));
    
      request(options, (err,resp, body) => {
        if( err ) {
          throw err;
        }
        console.log(util.inspect(body, false, null));
      });
    });
    
    module.exports.executeDelete = ((query) => {
      var options = {
        url : host + '/rest-ws/service/dms/batch/delete',
        method: 'POST',
        headers : {
          'accept' : 'application/json; charset=UTF-8'
        },
        auth : auth,
        json : query
      }
      console.log('Batch delete service url  : '+options.url);
      console.log('Batch delete service query:\n'+util.inspect(options.json, false, null));
    
      request(options, (err,resp, body) => {
        if( err ) {
          throw err;
        }
        console.log(util.inspect(body, false, null));
      });
    });


    Das Skript index.js enthält 2 beispielhafte Aufrufe der oben beschriebenen Endpunkte. 

    index.js
    const batch = require("./batchrunner.js")
    
    batch.executeUpdate(
      {
        query : {
          expression : '',
          type : 'lsydokument'
        },
        usercomment : 'Move',
        data : {
          "albumname" : {
            "parentref" : "album.name",
            "value" : "Horst"
          }
        },
        moveto : 'context',
        options : {
          breakonerror : true
        }
      }
    )
    
    batch.executeDelete(
      {
        query : {
          expression : '',
          type : 'album'
        },
        usercomment : 'Delete',
        options : {
          breakonerror : true,
          deleteonlyemptyfolders : true,
          harddelete : true
        }
      }
    )
  • Ausführung der Scripte

Die obigen Scripte können (nach der Installation von node.js) über die Kommandozeile per "node index.js" ausgeführt werden. Vorher muss mit 'npm install request' das request framework lokal installiert werden.

Alternativ zu node,js und den obigen Scripten können auch beliebige andere REST-WS fähige Clients verwendet werden. Hier wären insbesondere das Programm Postman, cURL oder ein Java Programm mit den apache httpcomponents zu erwähnen. Ein Beispiel für Letzteres kann bei Installierten (3.x oder 4.0) DMS-Service über http://localhost:8080/rest-ws/#PAGE:examples/java eingesehen werden.