From e9dfec05f3e37a122faa608f71738a296caa4dfd Mon Sep 17 00:00:00 2001
From: Lars Johansson <lars.johansson@ess.eu>
Date: Mon, 3 Jul 2023 17:44:13 +0200
Subject: [PATCH] Fix issue for verification of data migration for names,
 refactor endpoint paths, improve javadoc

Fix issue for verification of data migration for names.
Change names of methods and paths for endpoints.
Improve javadoc.
---
 .../controller/VerificationController.java    | 571 ++++++++++--------
 1 file changed, 320 insertions(+), 251 deletions(-)

diff --git a/src/main/java/org/openepics/names/rest/controller/VerificationController.java b/src/main/java/org/openepics/names/rest/controller/VerificationController.java
index c698f909..5dab1f70 100644
--- a/src/main/java/org/openepics/names/rest/controller/VerificationController.java
+++ b/src/main/java/org/openepics/names/rest/controller/VerificationController.java
@@ -64,15 +64,66 @@ import io.swagger.v3.oas.annotations.Hidden;
 /**
  * This part of REST API provides verification of data migration for Naming application.
  *
- * <p>Prerequisite(s)
+ * <p>
+ * Prerequisites.
+ * These are required to ensure that comparisons of content in old and migrated tables
+ * can be done and that result of comparisons are valid.
+ * <ul>
+ * <li>migration script run</li>
+ * <li>tables corresponding to both old and migrated database available</li>
+ * <li>must be done directly after migration has been done</li>
+ * <li>no changes of any kind in any way for content, either names or structures, may have been introduced</li>
+ * </ul>
+ *
+ * <p>
+ * Verification is preferably done in following order
+ * <ol>
+ * <li>structures</li>
+ * <li>names</li>
+ * <li>data is reachable</li>
+ * <li>comparison of old REST API vs. new REST API</li>
+ * </ol>
+ *
+ * <p>
+ * Structures.
+ * <ul>
+ * <li>Verification of structures (after) vs. name parts (before)</li>
+ * <li>Check that each attribute as expected in each structure entry</li>
+ * </ul>
+ *
+ * <p>
+ * Names.
+ * <ul>
+ * <li>Verification of names (after) vs. devices (before)</li>
+ * <li>Check that each attribute as expected in each name entry</li>
+ * </ul>
+ *
+ * <p>
+ * Data is reachable.
+ * <ul>
+ * <li>Verification of data in the sense that all data can be reached</li>
+ * <li>Concerns itself with new database, not old database</li>
+ * </ul>
+ *
+ * <p>
+ * Comparison of old REST API vs. new REST API.
+ * <ul>
+ * <li>Verification of differences between old REST API and new REST API</li>
+ * <li>Check that all content in new REST API is in old REST API and that difference is old/obsolete data</li>
+ * </ul>
+ *
+ * <p>
+ * Note
  * <ul>
- * <li>both old and migrated database available</li>
+ * <li>log statements and output are technical and implementation-like, and meant to give detailed information</li>
+ * <li>after migration has been done and verified, this part of REST API no longer holds any function and may be removed.
+ * As a suggestion, this may done in the second release of the software.</li>
  * </ul>
  *
  * <p>
  * Ideally, some knowledge of database tables and object structures acquired to dig into this class.
  * It can be done in any case and there is documentation available.
- * It is recommended to have database tables and object structures available.
+ * It is recommended to have database tables available in database management tool for any further queries.
  *
  * @author Lars Johansson
  */
@@ -86,10 +137,10 @@ public class VerificationController {
     //     global exception handler available
     //
     // methods
-    //     read      GET /verification/migration_devicerevision   - readMigrationDeviceRevision()
-    //     read      GET /verification/migration_namepartrevision - readMigrationNamePartRevision
-    //     read      GET /verification/data_reachable             - readDataReachable()
-    //     read      GET /verification/restapi_oldvsnew           - readRestApiOldVsNew()
+    //     read      GET /verification/migration_namepartrevision - readMigrationStructures
+    //     read      GET /verification/migration_devicerevision   - readMigrationNames
+    //     read      GET /verification/data_reachable             - readDataReachable
+    //     read      GET /verification/restapi_oldvsnew           - readRestApiOldVsNew
 
     private static final Logger LOGGER = Logger.getLogger(VerificationController.class.getName());
 
@@ -124,207 +175,33 @@ public class VerificationController {
     }
 
     /**
-     * Perform verification of data migration with focus on device revision.
+     * Perform verification of data migration with focus on structures, i.e. name part revisions.
      * Ok if all entries ok and no entry nok.
      *
      * @return report of data migration
      */
-    @GetMapping("/migration_devicerevision")
-    public String readMigrationDeviceRevision() {
-        // verification of
-        //     name vs. devicerevision, device
-        //     with help of namepartrevision, namepart
-
-        // note
-        //     check entry by entry
-        //     ----------
-        //     to check  1st, 2nd, 3rd parent to determine if systemgroup, system or subsystem
-        //     otherwise not clear how to make sure if it is supposed to be systemgroup and not system, subsystem and vice versa
-        //     ----------
-        //     date may be in different format for different objects, to be formatted before being compared
-        //     ----------
-        //     name.id                                = devicerevision.id
-        //     name.version                           = devicerevision.version
-        //     name.uuid                              = devicerevision.device_id             (device.id      --> device.uuid)
-        //     name.namepartrevision_systemgroup_uuid = devicerevision.section_id            (namepart.id    --> namepart.uuid
-        //     name.namepartrevision_system_uuid      = devicerevision.section_id            (namepart.id    --> namepart.uuid
-        //     name.namepartrevision_subsystem_uuid   = devicerevision.section_id            (namepart.id    --> namepart.uuid
-        //     name.namepartrevision_devicetype_uuid  = devicerevision.devicetype_id         (namepart.id    --> namepart.uuid
-        //     name.instance_index                    = devicerevision.instanceindex
-        //     name.convention_name                   = devicerevision.conventionname
-        //     name.convention_name_equivalence       = devicerevision.conventionnameeqclass
-        //     name.description                       = devicerevision.additionalinfo
-        //     name.status                            = null
-        //     name.latest                            = true if id = get max id for uuid     (not consider status)
-        //     name.deleted                           = devicerevision.deleted
-        //     name.requested                         = devicerevision.requestdate
-        //     name.requested_by                      = devicerevision.requestedby_id        (useraccount.id --> useraccount.username)
-        //     name.requested_comment                 = null
-        //     name.processed                         = null
-        //     name.processed_by                      = null
-        //     name.processed_comment                 = devicerevision.processorcomment
-
-        StringBuilder reportHtml = new StringBuilder();
-
-        // find data
-        //     for verification
-        //         names
-        //     to support
-        //         device names
-        //         name part revisions
-
-        List<Name>             names             = holderIRepositories.nameRepository().findAll();
-        List<DeviceRevision>   deviceNames       = deviceRevisionRepository.findAll();
-        List<NamePartRevision> namePartRevisions = namePartRevisionRepository.findAll();
-
-        prepareLogReport("readMigrationDeviceRevision, find data,     names.size:                       " + names.size(), reportHtml);
-        prepareLogReport("readMigrationDeviceRevision, find data,     deviceNames.size:                 " + deviceNames.size(), reportHtml);
-        prepareLogReport("readMigrationDeviceRevision, find data,     namePartRevisions.size:           " + namePartRevisions.size(), reportHtml);
-
-        // utility
-        //     interpret lists into hashmaps for faster retrieval in for loop below
-        //     used to help check name entries
-        //     ----------
-        //     mapIdDeviceRevision     - find corresponding (old) device revision for given id
-        //     mapUuidMaxIdName        - find out latest name id for given uuid
-        //     mapUuidNamePartRevision - find out name part revision for given uuid
-
-        HashMap<Long, DeviceRevision> mapIdDeviceRevision = new HashMap<>((int)(deviceNames.size()/0.75 + 2));
-        for (DeviceRevision deviceRevision : deviceNames) {
-            mapIdDeviceRevision.put(deviceRevision.getId(), deviceRevision);
-        }
-        HashMap<UUID, Long> mapUuidMaxIdName = new HashMap<>();
-        for (Name name : names) {
-            if (mapUuidMaxIdName.get(name.getUuid()) == null
-                    ||  name.getId() > mapUuidMaxIdName.get(name.getUuid())) {
-                mapUuidMaxIdName.put(name.getUuid(), name.getId());
-            }
-        }
-        HashMap<UUID, NamePartRevision> mapUuidNamePartRevision = new HashMap<>((int)(namePartRevisions.size()/0.75 + 2));
-        for (NamePartRevision namePartRevision : namePartRevisions) {
-            mapUuidNamePartRevision.put(namePartRevision.getNamePart().getUuid(), namePartRevision);
-        }
-
-        prepareLogReport("readMigrationDeviceRevision, utility,       mapIdDeviceRevision.size:         " + mapIdDeviceRevision.size(), reportHtml);
-        prepareLogReport("readMigrationDeviceRevision, utility,       mapUuidMaxIdName.size:            " + mapUuidMaxIdName.size(), reportHtml);
-        prepareLogReport("readMigrationDeviceRevision, utility,       mapUuidNamePartRevision.size:     " + mapUuidNamePartRevision.size(), reportHtml);
-
-        // keep track of id
-        //     ok
-        //     nok
-        SortedSet<Long> idOkDeviceRevisionDevice  = new TreeSet<>();
-        SortedSet<Long> idNokDeviceRevisionDevice = new TreeSet<>();
-
-        prepareLogReport("readMigrationDeviceRevision, check, before, idOkDeviceRevisionDevice.size:    " + idOkDeviceRevisionDevice.size(), reportHtml);
-        prepareLogReport("readMigrationDeviceRevision, check, before, idNokDeviceRevisionDevice.size:   " + idNokDeviceRevisionDevice.size(), reportHtml);
-
-        // name
-        // check entry by entry
-        //     each attribute as expected
-        boolean check = false;
-        DeviceRevision deviceRevision = null;
-        for (Name name : names) {
-            deviceRevision = mapIdDeviceRevision.get(name.getId());
-
-            check = deviceRevision != null;
-
-            check = check && name.getId().equals(deviceRevision.getId());
-            check = check && name.getVersion().equals(deviceRevision.getVersion());
-            check = check && name.getUuid().equals(deviceRevision.getDevice().getUuid());
-
-            // to check  1st, 2nd, 3rd parent to determine if systemgroup, system or subsystem
-            // otherwise not clear how to make sure if it is supposed to be systemgroup and not system, subsystem and vice versa
-            NamePartRevision parent1 = deviceRevision.getSection() != null
-                    ? mapUuidNamePartRevision.get(deviceRevision.getSection().getUuid())
-                    : null;
-            NamePartRevision parent2 = parent1 != null && parent1.getParent() != null
-                    ? mapUuidNamePartRevision.get(parent1.getParent().getUuid())
-                    : null;
-            NamePartRevision parent3 = parent2 != null && parent2.getParent() != null
-                    ? mapUuidNamePartRevision.get(parent2.getParent().getUuid())
-                    : null;
-            // parent 1    but not parent 2, 3 - system group
-            // parent 1, 2 but not parent 3    - system
-            // parent 1, 2, 3                  - subsystem
-            // else nok
-            UUID systemGroupUuid = name.getSystemGroupUuid();
-            UUID systemUuid = name.getSystemUuid();
-            UUID subsystemUuid = name.getSubsystemUuid();
-            UUID sectionUuid = deviceRevision.getSection().getUuid();
-            if (parent1 != null && parent2 == null && parent3 == null) {
-                check = check && sectionUuid.equals(systemGroupUuid) && systemUuid == null && subsystemUuid == null;
-            } else if (parent1 != null && parent2 != null && parent3 == null) {
-                check = check && sectionUuid.equals(systemUuid) && systemGroupUuid == null && subsystemUuid == null;
-            } else if (parent1 != null && parent2 != null && parent3 != null) {
-                check = check && sectionUuid.equals(subsystemUuid) && systemGroupUuid == null && systemUuid == null;
-            } else {
-                check = false;
-            }
-
-            check = check && ((name.getDeviceTypeUuid() == null && deviceRevision.getDeviceType() == null)
-                                || (name.getDeviceTypeUuid().equals(deviceRevision.getDeviceType().getUuid())));
-            check = check && StringUtils.equals(name.getInstanceIndex(), deviceRevision.getInstanceIndex());
-            check = check && StringUtils.equals(name.getConventionName(), deviceRevision.getConventionName());
-            check = check && StringUtils.equals(name.getConventionNameEquivalence(), deviceRevision.getConventionNameEqClass());
-            check = check && StringUtils.equals(name.getDescription(), deviceRevision.getAdditionalInfo());
-            check = check && name.getStatus() == null;
-
-            // latest
-            //     true if id = get max id for uuid
-            check = check && name.isLatest() == name.getId().equals(mapUuidMaxIdName.get(name.getUuid()));
-            check = check && name.isDeleted() == deviceRevision.isDeleted();
-
-            // date may be in different format for different objects, to be formatted before being compared
-            check = check && ((name.getRequested() == null && deviceRevision.getRequestDate() == null)
-                                || StringUtils.equals(SDF.format(name.getRequested()), SDF.format(deviceRevision.getRequestDate())));
-            check = check && StringUtils.equals(name.getRequestedBy(), deviceRevision.getRequestedBy().getUsername());
-            check = check && name.getRequestedComment() == null;
-            check = check && name.getProcessed() == null;
-            check = check && name.getProcessedBy() == null;
-            check = check && StringUtils.equals(name.getProcessedComment(), deviceRevision.getProcessorComment());
-
-            // add to count
-            if (check) {
-                idOkDeviceRevisionDevice.add(name.getId());
-            } else {
-                idNokDeviceRevisionDevice.add(name.getId());
-            }
-        }
-
-        // ok if
-        //     all entries ok
-        //     no entry nok
-        boolean ok = idOkDeviceRevisionDevice.size() == names.size()
-                && idNokDeviceRevisionDevice.isEmpty();
-
-        prepareLogReport("readMigrationDeviceRevision, check, after,  idOkDeviceRevisionDevice.size:    " + idOkDeviceRevisionDevice.size(), reportHtml);
-        prepareLogReport("readMigrationDeviceRevision, check, after,  idNokDeviceRevisionDevice.size:   " + idNokDeviceRevisionDevice.size(), reportHtml);
-        prepareLogReport("readMigrationDeviceRevision, ok: " + ok, reportHtml);
-
-        return reportHtml.toString();
-    }
-
-    /**
-     * Perform verification of data migration with focus on name part revision.
-     * Ok if all entries ok and no entry nok.
-     *
-     * @return report of data migration
-     */
-    @GetMapping("/migration_namepartrevision")
-    public String readMigrationNamePartRevision() {
-        // verification of
-        //     systemgroup
-        //     system
-        //     subsystem
-        //     discipline
-        //     devicegroup
-        //     devicetype
-        //         vs.
-        //     namepartrevision
-        //     with help of namepartrevision, namepart
-
-        // note
+    @GetMapping("/migration_structures")
+    public String readMigrationStructures() {
+        // about
+        //     verification of structures (after) vs. name parts (before)
+
+        // how
+        //     find data for verification
+        //         structures - systemgroup, system, subsystem, discipline, devicegroup, devicetype
+        //         name parts - namepartrevision, namepart
+        //     utility
+        //         interpret data into hashmaps for faster retrieval in checks
+        //     check
+        //         for each entry in each structure
+        //             check entry by entry
+        //                 each attribute as expected
+        //     ok if
+        //         all entries ok
+        //         no entry nok
+
+        // check
         //     check entry by entry
+        //         each attribute as expected
         //     ----------
         //     to check parent uuid
         //     ----------
@@ -352,15 +229,6 @@ public class VerificationController {
         StringBuilder reportHtml = new StringBuilder();
 
         // find data
-        //     for verification
-        //         system groups
-        //         systems
-        //         subsystems
-        //         disciplines
-        //         device groups
-        //         device types
-        //     to support
-        //         name part revisions
 
         List<SystemGroup>      systemGroups      = holderIRepositories.systemGroupRepository().findAll();
         List<System>           systems           = holderIRepositories.systemRepository().findAll();
@@ -370,13 +238,13 @@ public class VerificationController {
         List<DeviceType>       deviceTypes       = holderIRepositories.deviceTypeRepository().findAll();
         List<NamePartRevision> namePartRevisions = namePartRevisionRepository.findAll();
 
-        prepareLogReport("readMigrationNamePartRevision, find data,                systemGroups.size:            " + systemGroups.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, find data,                systems.size:                 " + systems.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, find data,                subsystems.size:              " + subsystems.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, find data,                disciplines.size:             " + disciplines.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, find data,                deviceGroups.size:            " + deviceGroups.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, find data,                deviceTypes.size:             " + deviceTypes.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, find data,                namePartRevisions.size:       " + namePartRevisions.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, find data,                systemGroups.size:            " + systemGroups.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, find data,                systems.size:                 " + systems.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, find data,                subsystems.size:              " + subsystems.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, find data,                disciplines.size:             " + disciplines.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, find data,                deviceGroups.size:            " + deviceGroups.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, find data,                deviceTypes.size:             " + deviceTypes.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, find data,                namePartRevisions.size:       " + namePartRevisions.size(), reportHtml);
 
         // utility
         //     interpret lists into hashmaps for faster retrieval in for loop below
@@ -443,13 +311,13 @@ public class VerificationController {
             }
         }
 
-        prepareLogReport("readMigrationNamePartRevision, utility,                  mapIdNamePartRevision.size:   " + mapIdNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, utility,                  mapUuidMaxIdSystemGroup.size: " + mapUuidMaxIdSystemGroup.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, utility,                  mapUuidMaxIdSystem.size:      " + mapUuidMaxIdSystem.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, utility,                  mapUuidMaxIdSubsystem.size:   " + mapUuidMaxIdSubsystem.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, utility,                  mapUuidMaxIdDiscipline.size:  " + mapUuidMaxIdDiscipline.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, utility,                  mapUuidMaxIdDeviceGroup.size: " + mapUuidMaxIdDeviceGroup.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, utility,                  mapUuidMaxIdDeviceType.size:  " + mapUuidMaxIdDeviceType.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, utility,                  mapIdNamePartRevision.size:   " + mapIdNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, utility,                  mapUuidMaxIdSystemGroup.size: " + mapUuidMaxIdSystemGroup.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, utility,                  mapUuidMaxIdSystem.size:      " + mapUuidMaxIdSystem.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, utility,                  mapUuidMaxIdSubsystem.size:   " + mapUuidMaxIdSubsystem.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, utility,                  mapUuidMaxIdDiscipline.size:  " + mapUuidMaxIdDiscipline.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, utility,                  mapUuidMaxIdDeviceGroup.size: " + mapUuidMaxIdDeviceGroup.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, utility,                  mapUuidMaxIdDeviceType.size:  " + mapUuidMaxIdDeviceType.size(), reportHtml);
 
         // keep track of id
         //     ok
@@ -457,12 +325,12 @@ public class VerificationController {
         SortedSet<Long> idOkNamePartRevision  = new TreeSet<>();
         SortedSet<Long> idNokNamePartRevision = new TreeSet<>();
 
-        prepareLogReport("readMigrationNamePartRevision, check, before,            idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, check, before,            idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, before,            idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, before,            idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
 
         // system group
         // check entry by entry
-        //         each attribute as expected
+        //     each attribute as expected
         boolean check = false;
         NamePartRevision namePartRevision = null;
         for (SystemGroup systemGroup : systemGroups) {
@@ -507,12 +375,12 @@ public class VerificationController {
                 idNokNamePartRevision.add(systemGroup.getId());
             }
         }
-        prepareLogReport("readMigrationNamePartRevision, check, after systemgroup, idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, check, after systemgroup, idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after systemgroup, idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after systemgroup, idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
 
         // system
         // check entry by entry
-        //         each attribute as expected
+        //     each attribute as expected
         for (System system : systems) {
             namePartRevision = mapIdNamePartRevision.get(system.getId());
 
@@ -556,12 +424,12 @@ public class VerificationController {
                 idNokNamePartRevision.add(system.getId());
             }
         }
-        prepareLogReport("readMigrationNamePartRevision, check, after system,      idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, check, after system,      idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after system,      idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after system,      idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
 
         // subsystem
         // check entry by entry
-        //         each attribute as expected
+        //     each attribute as expected
         for (Subsystem subsystem : subsystems) {
             namePartRevision = mapIdNamePartRevision.get(subsystem.getId());
 
@@ -605,12 +473,12 @@ public class VerificationController {
                 idNokNamePartRevision.add(subsystem.getId());
             }
         }
-        prepareLogReport("readMigrationNamePartRevision, check, after subsystem,   idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, check, after subsystem,   idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after subsystem,   idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after subsystem,   idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
 
         // discipline
         // check entry by entry
-        //         each attribute as expected
+        //     each attribute as expected
         for (Discipline discipline : disciplines) {
             namePartRevision = mapIdNamePartRevision.get(discipline.getId());
 
@@ -653,12 +521,12 @@ public class VerificationController {
                 idNokNamePartRevision.add(discipline.getId());
             }
         }
-        prepareLogReport("readMigrationNamePartRevision, check, after discipline,  idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, check, after discipline,  idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after discipline,  idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after discipline,  idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
 
         // device group
         // check entry by entry
-        //         each attribute as expected
+        //     each attribute as expected
         for (DeviceGroup deviceGroup : deviceGroups) {
             namePartRevision = mapIdNamePartRevision.get(deviceGroup.getId());
 
@@ -702,12 +570,12 @@ public class VerificationController {
                 idNokNamePartRevision.add(deviceGroup.getId());
             }
         }
-        prepareLogReport("readMigrationNamePartRevision, check, after devicegroup, idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, check, after devicegroup, idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after devicegroup, idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after devicegroup, idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
 
         // device type
         // check entry by entry
-        //         each attribute as expected
+        //     each attribute as expected
         for (DeviceType deviceType : deviceTypes) {
             namePartRevision = mapIdNamePartRevision.get(deviceType.getId());
 
@@ -751,8 +619,8 @@ public class VerificationController {
                 idNokNamePartRevision.add(deviceType.getId());
             }
         }
-        prepareLogReport("readMigrationNamePartRevision, check, after devicetype,  idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, check, after devicetype,  idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after devicetype,  idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after devicetype,  idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
 
         // ok if
         //     all entries ok
@@ -760,9 +628,210 @@ public class VerificationController {
         boolean ok = idOkNamePartRevision.size() == namePartRevisions.size()
                 && idNokNamePartRevision.isEmpty();
 
-        prepareLogReport("readMigrationNamePartRevision, check, after,             idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, check, after,             idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
-        prepareLogReport("readMigrationNamePartRevision, ok:  " + ok, reportHtml);
+        prepareLogReport("readMigrationStructures, check, after,             idOkNamePartRevision.size:    " + idOkNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, check, after,             idNokNamePartRevision.size:   " + idNokNamePartRevision.size(), reportHtml);
+        prepareLogReport("readMigrationStructures, ok:  " + ok, reportHtml);
+
+        return reportHtml.toString();
+    }
+
+    /**
+     * Perform verification of data migration with focus on names, i.e. device revisions.
+     * Ok if all entries ok and no entry nok.
+     *
+     * @return report of data migration
+     */
+    @GetMapping("/migration_names")
+    public String readMigrationNames() {
+        // about
+        //     verification of names (after) vs. devices (before)
+
+        // how
+        //     find data for verification
+        //         names   - name
+        //         devices - devicerevision, device
+        //         with help of namepartrevision, namepart
+        //     utility
+        //         interpret data into hashmaps for faster retrieval in checks
+        //     check
+        //         for each name
+        //             check entry by entry
+        //                 each attribute as expected
+        //     ok if
+        //         all entries ok
+        //         no entry nok
+
+        // check
+        //     check entry by entry
+        //         each attribute as expected
+        //     ----------
+        //     to check  1st, 2nd, 3rd parent to determine if systemgroup, system or subsystem
+        //     otherwise not clear how to make sure if it is supposed to be systemgroup and not system, subsystem and vice versa
+        //     ----------
+        //     date may be in different format for different objects, to be formatted before being compared
+        //     ----------
+        //     name.id                                = devicerevision.id
+        //     name.version                           = devicerevision.version
+        //     name.uuid                              = devicerevision.device_id             (device.id      --> device.uuid)
+        //     name.namepartrevision_systemgroup_uuid = devicerevision.section_id            (namepart.id    --> namepart.uuid
+        //     name.namepartrevision_system_uuid      = devicerevision.section_id            (namepart.id    --> namepart.uuid
+        //     name.namepartrevision_subsystem_uuid   = devicerevision.section_id            (namepart.id    --> namepart.uuid
+        //     name.namepartrevision_devicetype_uuid  = devicerevision.devicetype_id         (namepart.id    --> namepart.uuid
+        //     name.instance_index                    = devicerevision.instanceindex
+        //     name.convention_name                   = devicerevision.conventionname
+        //     name.convention_name_equivalence       = devicerevision.conventionnameeqclass
+        //     name.description                       = devicerevision.additionalinfo
+        //     name.status                            = null
+        //     name.latest                            = true if id = get max id for uuid     (not consider status)
+        //     name.deleted                           = devicerevision.deleted
+        //     name.requested                         = devicerevision.requestdate
+        //     name.requested_by                      = devicerevision.requestedby_id        (useraccount.id --> useraccount.username)
+        //     name.requested_comment                 = null
+        //     name.processed                         = null
+        //     name.processed_by                      = null
+        //     name.processed_comment                 = devicerevision.processorcomment
+
+        StringBuilder reportHtml = new StringBuilder();
+
+        // find data
+
+        List<Name>             names             = holderIRepositories.nameRepository().findAll();
+        List<DeviceRevision>   deviceNames       = deviceRevisionRepository.findAll();
+        List<NamePartRevision> namePartRevisions = namePartRevisionRepository.findAll();
+
+        prepareLogReport("readMigrationNames, find data,     names.size:                       " + names.size(), reportHtml);
+        prepareLogReport("readMigrationNames, find data,     deviceNames.size:                 " + deviceNames.size(), reportHtml);
+        prepareLogReport("readMigrationNames, find data,     namePartRevisions.size:           " + namePartRevisions.size(), reportHtml);
+
+        // utility
+        //     interpret lists into hashmaps for faster retrieval in for loop below
+        //     used to help check name entries
+        //     ----------
+        //     mapIdDeviceRevision     - find corresponding (old) device revision for given id
+        //     mapUuidMaxIdName        - find out latest name id for given uuid
+        //     mapUuidNamePartRevision - find out name part revision for given uuid
+
+        HashMap<Long, DeviceRevision> mapIdDeviceRevision = new HashMap<>((int)(deviceNames.size()/0.75 + 2));
+        for (DeviceRevision deviceRevision : deviceNames) {
+            mapIdDeviceRevision.put(deviceRevision.getId(), deviceRevision);
+        }
+        HashMap<UUID, Long> mapUuidMaxIdName = new HashMap<>();
+        for (Name name : names) {
+            if (mapUuidMaxIdName.get(name.getUuid()) == null
+                    ||  name.getId() > mapUuidMaxIdName.get(name.getUuid())) {
+                mapUuidMaxIdName.put(name.getUuid(), name.getId());
+            }
+        }
+        HashMap<UUID, NamePartRevision> mapUuidNamePartRevision = new HashMap<>((int)(namePartRevisions.size()/0.75 + 2));
+        for (NamePartRevision namePartRevision : namePartRevisions) {
+            mapUuidNamePartRevision.put(namePartRevision.getNamePart().getUuid(), namePartRevision);
+        }
+
+        prepareLogReport("readMigrationNames, utility,       mapIdDeviceRevision.size:         " + mapIdDeviceRevision.size(), reportHtml);
+        prepareLogReport("readMigrationNames, utility,       mapUuidMaxIdName.size:            " + mapUuidMaxIdName.size(), reportHtml);
+        prepareLogReport("readMigrationNames, utility,       mapUuidNamePartRevision.size:     " + mapUuidNamePartRevision.size(), reportHtml);
+
+        // keep track of id
+        //     ok
+        //     nok
+        SortedSet<Long> idOkDeviceRevisionDevice  = new TreeSet<>();
+        SortedSet<Long> idNokDeviceRevisionDevice = new TreeSet<>();
+
+        prepareLogReport("readMigrationNames, check, before, idOkDeviceRevisionDevice.size:    " + idOkDeviceRevisionDevice.size(), reportHtml);
+        prepareLogReport("readMigrationNames, check, before, idNokDeviceRevisionDevice.size:   " + idNokDeviceRevisionDevice.size(), reportHtml);
+
+        // name
+        // check entry by entry
+        //     each attribute as expected
+        boolean check = false;
+        DeviceRevision deviceRevision = null;
+        try {
+        for (Name name : names) {
+            // e.g. if there has been usage of new database tables (new entries) before verification, there are more rows in those tables
+            //     which means new and more ids than in old database tables
+            //     which means those new ids don't exist in old database tables
+            //     --> retrieval of device revisions for those ids will give null
+
+            deviceRevision = mapIdDeviceRevision.get(name.getId());
+            check = deviceRevision != null;
+
+            if (check) {
+                check = check && name.getId().equals(deviceRevision.getId());
+                check = check && name.getVersion().equals(deviceRevision.getVersion());
+                check = check && name.getUuid().equals(deviceRevision.getDevice().getUuid());
+
+                // to check  1st, 2nd, 3rd parent to determine if systemgroup, system or subsystem
+                // otherwise not clear how to make sure if it is supposed to be systemgroup and not system, subsystem and vice versa
+                NamePartRevision parent1 = deviceRevision.getSection() != null
+                        ? mapUuidNamePartRevision.get(deviceRevision.getSection().getUuid())
+                        : null;
+                NamePartRevision parent2 = parent1 != null && parent1.getParent() != null
+                        ? mapUuidNamePartRevision.get(parent1.getParent().getUuid())
+                        : null;
+                NamePartRevision parent3 = parent2 != null && parent2.getParent() != null
+                        ? mapUuidNamePartRevision.get(parent2.getParent().getUuid())
+                        : null;
+                // parent 1    but not parent 2, 3 - system group
+                // parent 1, 2 but not parent 3    - system
+                // parent 1, 2, 3                  - subsystem
+                // else nok
+                UUID systemGroupUuid = name.getSystemGroupUuid();
+                UUID systemUuid = name.getSystemUuid();
+                UUID subsystemUuid = name.getSubsystemUuid();
+                UUID sectionUuid = deviceRevision.getSection().getUuid();
+                if (parent1 != null && parent2 == null && parent3 == null) {
+                    check = check && sectionUuid.equals(systemGroupUuid) && systemUuid == null && subsystemUuid == null;
+                } else if (parent1 != null && parent2 != null && parent3 == null) {
+                    check = check && sectionUuid.equals(systemUuid) && systemGroupUuid == null && subsystemUuid == null;
+                } else if (parent1 != null && parent2 != null && parent3 != null) {
+                    check = check && sectionUuid.equals(subsystemUuid) && systemGroupUuid == null && systemUuid == null;
+                } else {
+                    check = false;
+                }
+
+                check = check && ((name.getDeviceTypeUuid() == null && deviceRevision.getDeviceType() == null)
+                                    || (name.getDeviceTypeUuid().equals(deviceRevision.getDeviceType().getUuid())));
+                check = check && StringUtils.equals(name.getInstanceIndex(), deviceRevision.getInstanceIndex());
+                check = check && StringUtils.equals(name.getConventionName(), deviceRevision.getConventionName());
+                check = check && StringUtils.equals(name.getConventionNameEquivalence(), deviceRevision.getConventionNameEqClass());
+                check = check && StringUtils.equals(name.getDescription(), deviceRevision.getAdditionalInfo());
+                check = check && name.getStatus() == null;
+
+                // latest
+                //     true if id = get max id for uuid
+                check = check && name.isLatest() == name.getId().equals(mapUuidMaxIdName.get(name.getUuid()));
+                check = check && name.isDeleted() == deviceRevision.isDeleted();
+
+                // date may be in different format for different objects, to be formatted before being compared
+                check = check && ((name.getRequested() == null && deviceRevision.getRequestDate() == null)
+                                    || StringUtils.equals(SDF.format(name.getRequested()), SDF.format(deviceRevision.getRequestDate())));
+                check = check && StringUtils.equals(name.getRequestedBy(), deviceRevision.getRequestedBy().getUsername());
+                check = check && name.getRequestedComment() == null;
+                check = check && name.getProcessed() == null;
+                check = check && name.getProcessedBy() == null;
+                check = check && StringUtils.equals(name.getProcessedComment(), deviceRevision.getProcessorComment());
+            }
+
+            // add to count
+            if (check) {
+                idOkDeviceRevisionDevice.add(name.getId());
+            } else {
+                idNokDeviceRevisionDevice.add(name.getId());
+            }
+        }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        // ok if
+        //     all entries ok
+        //     no entry nok
+        boolean ok = idOkDeviceRevisionDevice.size() == names.size()
+                && idNokDeviceRevisionDevice.isEmpty();
+
+        prepareLogReport("readMigrationNames, check, after,  idOkDeviceRevisionDevice.size:    " + idOkDeviceRevisionDevice.size(), reportHtml);
+        prepareLogReport("readMigrationNames, check, after,  idNokDeviceRevisionDevice.size:   " + idNokDeviceRevisionDevice.size(), reportHtml);
+        prepareLogReport("readMigrationNames, ok: " + ok, reportHtml);
 
         return reportHtml.toString();
     }
@@ -770,7 +839,7 @@ public class VerificationController {
     // ----------------------------------------------------------------------------------------------------
 
     /**
-     * Perform verification of data in sense that all data can be reached. Current data is one thing but suggested data (pending) and old data (obsolete) is another thing.
+     * Perform verification of data in the sense that all data can be reached. Current data is one thing but suggested data (pending) and old data (obsolete) is another thing.
      * All data reached verification can be done like selecting all entries from tables (names, system group, system, subsystem, discipline, device group, device type)
      * and then take uuid and retrieve history for uuid. By that, all entries should be reached. In a sense, select distinct uuid, then retrieve history by uuid,
      * all ids should be encompassed by looking at all returned rows. Requires a couple of for loops and maps and sets to keep track of things.
@@ -909,7 +978,7 @@ public class VerificationController {
     }
 
     /**
-     * Verify difference between old REST API and new REST API.
+     * Perform verification of differences between old REST API and new REST API.
      *
      * Amount is less in new than in old. Verify that all content in new REST API is in old REST API and that difference is old/obsolete data.
      *
-- 
GitLab