From 29bc3796b14077028c941198c875d080b4507482 Mon Sep 17 00:00:00 2001
From: Lars Johansson <lars.johansson@ess.eu>
Date: Thu, 24 Feb 2022 08:58:44 +0100
Subject: [PATCH] Added existing REST API endpoints - deviceNames, healthcheck,
 history, parts - for proof-of-concept

---
 .../old/business/NameRevisionStatus.java      |  71 +++
 .../old/model/NamePartRevisionStatus.java     |  85 +++
 .../repository/IDeviceGroupRepository.java    |  63 +++
 .../repository/IDeviceTypeRepository.java     |  63 +++
 .../repository/IDisciplineRepository.java     |  57 ++
 .../names/repository/INameRepository.java     |  99 ++++
 .../repository/ISubsystemRepository.java      |  63 +++
 .../repository/ISystemGroupRepository.java    |  57 ++
 .../names/repository/ISystemRepository.java   |  63 +++
 .../names/repository/model/DeviceGroup.java   | 120 +++++
 .../names/repository/model/DeviceType.java    | 120 +++++
 .../names/repository/model/Discipline.java    | 102 ++++
 .../names/repository/model/Name.java          | 196 +++++++
 .../names/repository/model/NameStructure.java | 214 ++++++++
 .../names/repository/model/Persistable.java   |  85 +++
 .../names/repository/model/Structure.java     | 105 ++++
 .../names/repository/model/Subsystem.java     | 120 +++++
 .../names/repository/model/System.java        | 120 +++++
 .../names/repository/model/SystemGroup.java   | 102 ++++
 .../openepics/names/rest/beans/Status.java    |  34 ++
 .../rest/beans/old/DeviceNameElement.java     | 208 ++++++++
 .../names/rest/beans/old/HistoryElement.java  | 170 ++++++
 .../names/rest/beans/old/PartElement.java     | 188 +++++++
 .../old/DeviceNamesControllerV0.java          | 499 ++++++++++++++++++
 .../old/HealthcheckControllerV0.java          |  62 +++
 .../controller/old/HistoryControllerV0.java   | 262 +++++++++
 .../rest/controller/old/PartControllerV0.java | 299 +++++++++++
 .../names/util/HolderIRepositories.java       | 133 +++++
 .../util/HolderSystemDeviceStructure.java     | 241 +++++++++
 .../org/openepics/names/util/NameUtil.java    | 213 ++++++++
 .../names/util/NamingConventionUtil.java      | 461 ++++++++++++++++
 .../names/util/old/DeviceNameElementUtil.java | 207 ++++++++
 .../names/util/old/HistoryElementUtil.java    | 343 ++++++++++++
 .../names/util/old/PartElementUtil.java       | 176 ++++++
 .../names/NamingApplicationTests.java         |  31 ++
 .../openepics/names/util/NameUtilTest.java    |  93 ++++
 .../names/util/NamingConventionUtilTest.java  | 442 ++++++++++++++++
 37 files changed, 5967 insertions(+)
 create mode 100644 src/main/java/org/openepics/names/old/business/NameRevisionStatus.java
 create mode 100644 src/main/java/org/openepics/names/old/model/NamePartRevisionStatus.java
 create mode 100644 src/main/java/org/openepics/names/repository/IDeviceGroupRepository.java
 create mode 100644 src/main/java/org/openepics/names/repository/IDeviceTypeRepository.java
 create mode 100644 src/main/java/org/openepics/names/repository/IDisciplineRepository.java
 create mode 100644 src/main/java/org/openepics/names/repository/INameRepository.java
 create mode 100644 src/main/java/org/openepics/names/repository/ISubsystemRepository.java
 create mode 100644 src/main/java/org/openepics/names/repository/ISystemGroupRepository.java
 create mode 100644 src/main/java/org/openepics/names/repository/ISystemRepository.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/DeviceGroup.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/DeviceType.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/Discipline.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/Name.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/NameStructure.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/Persistable.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/Structure.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/Subsystem.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/System.java
 create mode 100644 src/main/java/org/openepics/names/repository/model/SystemGroup.java
 create mode 100644 src/main/java/org/openepics/names/rest/beans/Status.java
 create mode 100644 src/main/java/org/openepics/names/rest/beans/old/DeviceNameElement.java
 create mode 100644 src/main/java/org/openepics/names/rest/beans/old/HistoryElement.java
 create mode 100644 src/main/java/org/openepics/names/rest/beans/old/PartElement.java
 create mode 100644 src/main/java/org/openepics/names/rest/controller/old/DeviceNamesControllerV0.java
 create mode 100644 src/main/java/org/openepics/names/rest/controller/old/HealthcheckControllerV0.java
 create mode 100644 src/main/java/org/openepics/names/rest/controller/old/HistoryControllerV0.java
 create mode 100644 src/main/java/org/openepics/names/rest/controller/old/PartControllerV0.java
 create mode 100644 src/main/java/org/openepics/names/util/HolderIRepositories.java
 create mode 100644 src/main/java/org/openepics/names/util/HolderSystemDeviceStructure.java
 create mode 100644 src/main/java/org/openepics/names/util/NameUtil.java
 create mode 100644 src/main/java/org/openepics/names/util/NamingConventionUtil.java
 create mode 100644 src/main/java/org/openepics/names/util/old/DeviceNameElementUtil.java
 create mode 100644 src/main/java/org/openepics/names/util/old/HistoryElementUtil.java
 create mode 100644 src/main/java/org/openepics/names/util/old/PartElementUtil.java
 create mode 100644 src/test/java/org/openepics/names/NamingApplicationTests.java
 create mode 100644 src/test/java/org/openepics/names/util/NameUtilTest.java
 create mode 100644 src/test/java/org/openepics/names/util/NamingConventionUtilTest.java

diff --git a/src/main/java/org/openepics/names/old/business/NameRevisionStatus.java b/src/main/java/org/openepics/names/old/business/NameRevisionStatus.java
new file mode 100644
index 0000000..fcce8e9
--- /dev/null
+++ b/src/main/java/org/openepics/names/old/business/NameRevisionStatus.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.old.business;
+
+import org.openepics.names.old.model.NamePartRevisionStatus;
+
+/**
+ * Enum that handles the status of a revision.
+ *
+ * @author karinrathsman
+ *
+ */
+public enum NameRevisionStatus {
+    APPROVED(),
+    CANCELLED(),
+    PENDING(),
+    REJECTED();
+
+    static NameRevisionStatus get(NamePartRevisionStatus status) {
+        // To change body of generated methods, choose Tools | Templates.
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     *
+     * @return true if the revision is unapproved and pending
+     */
+    public boolean isPending() {
+        return equals(PENDING);
+    }
+
+    /**
+     *
+     * @return true if the revision approved
+     */
+    public boolean isApproved() {
+        return equals(APPROVED);
+    }
+
+    /**
+     *
+     * @return true if the revision is unapproved and cancelled or rejcted
+     */
+    public boolean isCancelled() {
+        return equals(CANCELLED) || equals(REJECTED);
+    }
+
+    /**
+     *
+     * @return true if the revision is unapproved and rejcted
+     */
+    public boolean isRejected() {
+        return equals(REJECTED);
+    }
+}
diff --git a/src/main/java/org/openepics/names/old/model/NamePartRevisionStatus.java b/src/main/java/org/openepics/names/old/model/NamePartRevisionStatus.java
new file mode 100644
index 0000000..553ef52
--- /dev/null
+++ b/src/main/java/org/openepics/names/old/model/NamePartRevisionStatus.java
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2014 European Spallation Source ERIC.
+ * Copyright (c) 2014 Cosylab d.d.
+ *
+ * This file is part of Naming Service.
+ * Naming Service is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 2 of the License, or any newer version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see https://www.gnu.org/licenses/gpl-2.0.txt
+ */
+
+package org.openepics.names.old.model;
+
+import org.openepics.names.old.business.NameRevisionStatus;
+
+/**
+ * Status of the name part in the request / approve workflow.
+ *
+ * @author Marko Kolar
+ */
+public enum NamePartRevisionStatus {
+
+    /**
+     * The proposed revision has been approved by the administrator.
+     */
+    APPROVED,
+    /**
+     * The proposed revision has been cancelled by the user that requested it.
+     */
+    CANCELLED,
+    /**
+     * The proposed revision is pending approval by the administrator.
+     */
+    PENDING,
+    /**
+     * The proposed revision has been rejected by the administrator.
+     */
+    REJECTED;
+
+    /**
+     * Convert NamePartRevisionStatus to NameRevisionStatus.
+     *
+     * @param status NamePartRevisionStatus
+     * @return NameRevisionStatus
+     */
+    public static NameRevisionStatus asNameRevisionStatus(NamePartRevisionStatus status) {
+        switch (status) {
+            case APPROVED:
+                return NameRevisionStatus.APPROVED;
+            case CANCELLED:
+                return NameRevisionStatus.CANCELLED;
+            case REJECTED:
+                return NameRevisionStatus.REJECTED;
+            default:
+                return NameRevisionStatus.PENDING;
+        }
+    }
+
+    /**
+     * Convert NameRevisionStatus to NamePartRevisionStatus.
+     *
+     * @param status NameRevisionStatus
+     * @return NamePartRevisionStatus
+     */
+    public static NamePartRevisionStatus get(NameRevisionStatus status) {
+        switch (status) {
+            case APPROVED:
+                return APPROVED;
+            case CANCELLED:
+                return CANCELLED;
+            case REJECTED:
+                return REJECTED;
+            default:
+                return PENDING;
+        }
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/IDeviceGroupRepository.java b/src/main/java/org/openepics/names/repository/IDeviceGroupRepository.java
new file mode 100644
index 0000000..3bbea85
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/IDeviceGroupRepository.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository;
+
+import java.util.List;
+
+import org.openepics.names.repository.model.DeviceGroup;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Find device group structure (name part) information from JPA.
+ *
+ * @author Lars Johansson
+ */
+@Repository
+public interface IDeviceGroupRepository extends JpaRepository<DeviceGroup, Long> {
+
+    @Query("FROM DeviceGroup dg WHERE dg.latest = true AND dg.uuid = ?1")
+    DeviceGroup findLatestByUuid(String uuid);
+
+    @Query("FROM DeviceGroup dg WHERE dg.latest = true AND dg.deleted = false AND dg.mnemonic = ?1")
+    DeviceGroup findLatestNotDeletedByMnemonic(String mnemonic);
+
+    @Query("FROM DeviceGroup dg WHERE dg.latest = true AND dg.deleted = false AND dg.uuid = ?1")
+    DeviceGroup findLatestNotDeletedByUuid(String uuid);
+
+    @Query("FROM DeviceGroup dg WHERE dg.latest = true AND dg.deleted = false AND dg.parent_uuid = ?1 and dg.mnemonic = ?2")
+    DeviceGroup findLatestNotDeletedByParentAndMnemonic(String uuid, String mnemonic);
+
+    @Query("FROM DeviceGroup dg WHERE dg.uuid = ?1")
+    List<DeviceGroup> findByUuid(String uuid);
+
+    @Query("FROM DeviceGroup dg WHERE dg.latest = true")
+    List<DeviceGroup> findLatest();
+
+    @Query("FROM DeviceGroup dg WHERE dg.latest = true AND dg.mnemonic = ?1")
+    List<DeviceGroup> findLatestByMnemonic(String mnemonic);
+
+    @Query("FROM DeviceGroup dg WHERE dg.latest = true AND dg.deleted = false")
+    List<DeviceGroup> findLatestNotDeleted();
+
+    @Query("FROM DeviceGroup dg WHERE dg.latest = true AND dg.deleted = false AND dg.parent_uuid = ?1")
+    List<DeviceGroup> findLatestNotDeletedByParent(String uuid);
+
+}
diff --git a/src/main/java/org/openepics/names/repository/IDeviceTypeRepository.java b/src/main/java/org/openepics/names/repository/IDeviceTypeRepository.java
new file mode 100644
index 0000000..3aa16b5
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/IDeviceTypeRepository.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository;
+
+import java.util.List;
+
+import org.openepics.names.repository.model.DeviceType;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Find device type structure (name part) information from JPA.
+ *
+ * @author Lars Johansson
+ */
+@Repository
+public interface IDeviceTypeRepository extends JpaRepository<DeviceType, Long> {
+
+    @Query("FROM DeviceType dt WHERE dt.latest = true AND dt.uuid = ?1")
+    DeviceType findLatestByUuid(String uuid);
+
+    @Query("FROM DeviceType dt WHERE dt.latest = true AND dt.deleted = false AND dt.mnemonic = ?1")
+    DeviceType findLatestNotDeletedByMnemonic(String mnemonic);
+
+    @Query("FROM DeviceType dt WHERE dt.latest = true AND dt.deleted = false AND dt.uuid = ?1")
+    DeviceType findLatestNotDeletedByUuid(String uuid);
+
+    @Query("FROM DeviceType dt WHERE dt.latest = true AND dt.deleted = false AND dt.parent_uuid = ?1 and dt.mnemonic = ?2")
+    DeviceType findLatestNotDeletedByParentAndMnemonic(String uuid, String mnemonic);
+
+    @Query("FROM DeviceType dt WHERE dt.uuid = ?1")
+    List<DeviceType> findByUuid(String uuid);
+
+    @Query("FROM DeviceType dt WHERE dt.latest = true")
+    List<DeviceType> findLatest();
+
+    @Query("FROM DeviceType dt WHERE dt.latest = true AND dt.mnemonic = ?1")
+    List<DeviceType> findLatestByMnemonic(String mnemonic);
+
+    @Query("FROM DeviceType dt WHERE dt.latest = true AND dt.deleted = false")
+    List<DeviceType> findLatestNotDeleted();
+
+    @Query("FROM DeviceType dt WHERE dt.latest = true AND dt.deleted = false AND dt.parent_uuid = ?1")
+    List<DeviceType> findLatestNotDeletedByParent(String uuid);
+
+}
diff --git a/src/main/java/org/openepics/names/repository/IDisciplineRepository.java b/src/main/java/org/openepics/names/repository/IDisciplineRepository.java
new file mode 100644
index 0000000..747363b
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/IDisciplineRepository.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository;
+
+import java.util.List;
+
+import org.openepics.names.repository.model.Discipline;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Find discipline structure (name part) information from JPA.
+ *
+ * @author Lars Johansson
+ */
+@Repository
+public interface IDisciplineRepository extends JpaRepository<Discipline, Long> {
+
+    @Query("FROM Discipline di WHERE di.latest = true AND di.uuid = ?1")
+    Discipline findLatestByUuid(String uuid);
+
+    @Query("FROM Discipline di WHERE di.latest = true AND di.deleted = false AND di.mnemonic = ?1")
+    Discipline findLatestNotDeletedByMnemonic(String mnemonic);
+
+    @Query("FROM Discipline di WHERE di.latest = true AND di.deleted = false AND di.uuid = ?1")
+    Discipline findLatestNotDeletedByUuid(String uuid);
+
+    @Query("FROM Discipline di WHERE di.uuid = ?1")
+    List<Discipline> findByUuid(String uuid);
+
+    @Query("FROM Discipline di WHERE di.latest = true")
+    List<Discipline> findLatest();
+
+    @Query("FROM Discipline di WHERE di.latest = true AND di.mnemonic = ?1")
+    List<Discipline> findLatestByMnemonic(String mnemonic);
+
+    @Query("FROM Discipline di WHERE di.latest = true AND di.deleted = false")
+    List<Discipline> findLatestNotDeleted();
+
+}
diff --git a/src/main/java/org/openepics/names/repository/INameRepository.java b/src/main/java/org/openepics/names/repository/INameRepository.java
new file mode 100644
index 0000000..3a1fbb2
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/INameRepository.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository;
+
+import java.util.List;
+
+import org.openepics.names.repository.model.Name;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Find name information from JPA.
+ *
+ * @author Lars Johansson
+ */
+@Repository
+public interface INameRepository extends JpaRepository<Name, Long> {
+
+    @Query("FROM Name n WHERE n.latest = true AND n.uuid = ?1")
+    Name findLatestByUuid(String uuid);
+
+    @Query("FROM Name n WHERE n.latest = true AND n.convention_name = ?1")
+    Name findLatestByConventionName(String conventionName);
+
+    @Query("FROM Name n WHERE n.uuid = ?1")
+    List<Name> findByUuid(String uuid);
+
+    @Query("FROM Name n WHERE n.latest = true")
+    List<Name> findLatest();
+
+    @Query("FROM Name n WHERE n.latest = true AND n.deleted = false")
+    List<Name> findLatestNotDeleted();
+
+    @Query("SELECT n FROM Name n, SystemGroup sg "
+            + "WHERE n.latest = true "
+            + "AND sg.uuid = n.systemgroup_uuid "
+            + "AND sg.latest = true "
+            + "AND sg.mnemonic = ?1")
+    List<Name> findLatestBySystemGroupMnemonic(String mnemonic);
+
+    @Query("SELECT n FROM Name n, System sys "
+            + "WHERE n.latest = true "
+            + "AND sys.uuid = n.system_uuid "
+            + "AND sys.latest = true "
+            + "AND sys.mnemonic = ?1")
+    List<Name> findLatestBySystemMnemonic(String mnemonic);
+
+    @Query("SELECT n FROM Name n, Subsystem sub, System sys "
+            + "WHERE n.latest = true "
+            + "AND sub.uuid = n.subsystem_uuid "
+            + "AND sub.latest = true "
+            + "AND sys.uuid = sub.parent_uuid  "
+            + "AND sys.latest = true "
+            + "AND sys.mnemonic = ?1")
+    List<Name> findLatestBySystemMnemonicThroughSubsystem(String mnemonic);
+
+    @Query("SELECT n FROM Name n, Subsystem sub "
+            + "WHERE n.latest = true "
+            + "AND sub.uuid = n.subsystem_uuid "
+            + "AND sub.latest = true "
+            + "AND sub.mnemonic = ?1")
+    List<Name> findLatestBySubsystemMnemonic(String mnemonic);
+
+    @Query("SELECT n FROM Name n, DeviceType dt, DeviceGroup dg, Discipline di "
+            + "WHERE n.latest = true "
+            + "AND dt.uuid = n.devicetype_uuid "
+            + "AND dt.latest = true "
+            + "AND dg.uuid = dt.parent_uuid "
+            + "AND dg.latest = true "
+            + "AND di.uuid = dg.parent_uuid "
+            + "AND di.latest = true "
+            + "AND di.mnemonic = ?1")
+    List<Name> findLatestByDisciplineMnemonic(String mnemonic);
+
+    @Query("SELECT n FROM Name n, DeviceType dt "
+            + "WHERE n.latest = true "
+            + "AND dt.uuid = n.devicetype_uuid "
+            + "AND dt.latest = true "
+            + "AND dt.mnemonic = ?1")
+    List<Name> findLatestByDeviceTypeMnemonic(String mnemonic);
+
+}
diff --git a/src/main/java/org/openepics/names/repository/ISubsystemRepository.java b/src/main/java/org/openepics/names/repository/ISubsystemRepository.java
new file mode 100644
index 0000000..29eeadd
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/ISubsystemRepository.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository;
+
+import java.util.List;
+
+import org.openepics.names.repository.model.Subsystem;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Find subsystem structure (name part)information from JPA.
+ *
+ * @author Lars Johansson
+ */
+@Repository
+public interface ISubsystemRepository extends JpaRepository<Subsystem, Long> {
+
+    @Query("FROM Subsystem sub WHERE sub.latest = true AND sub.uuid = ?1")
+    Subsystem findLatestByUuid(String uuid);
+
+    @Query("FROM Subsystem sub WHERE sub.latest = true AND sub.deleted = false AND sub.mnemonic = ?1")
+    Subsystem findLatestNotDeletedByMnemonic(String mnemonic);
+
+    @Query("FROM Subsystem sub WHERE sub.latest = true AND sub.deleted = false AND sub.uuid = ?1")
+    Subsystem findLatestNotDeletedByUuid(String uuid);
+
+    @Query("FROM Subsystem sub WHERE sub.latest = true AND sub.deleted = false AND sub.parent_uuid = ?1 and sub.mnemonic = ?2")
+    Subsystem findLatestNotDeletedByParentAndMnemonic(String uuid, String mnemonic);
+
+    @Query("FROM Subsystem sub WHERE sub.uuid = ?1")
+    List<Subsystem> findByUuid(String uuid);
+
+    @Query("FROM Subsystem sub WHERE sub.latest = true")
+    List<Subsystem> findLatest();
+
+    @Query("FROM Subsystem sub WHERE sub.latest = true AND sub.mnemonic = ?1")
+    List<Subsystem> findLatestByMnemonic(String mnemonic);
+
+    @Query("FROM Subsystem sub WHERE sub.latest = true AND sub.deleted = false")
+    List<Subsystem> findLatestNotDeleted();
+
+    @Query("FROM Subsystem sub WHERE sub.latest = true AND sub.deleted = false AND sub.parent_uuid = ?1")
+    List<Subsystem> findLatestNotDeletedByParent(String uuid);
+
+}
diff --git a/src/main/java/org/openepics/names/repository/ISystemGroupRepository.java b/src/main/java/org/openepics/names/repository/ISystemGroupRepository.java
new file mode 100644
index 0000000..a61bbdf
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/ISystemGroupRepository.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository;
+
+import java.util.List;
+
+import org.openepics.names.repository.model.SystemGroup;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Find system group structure (name part) information from JPA.
+ *
+ * @author Lars Johansson
+ */
+@Repository
+public interface ISystemGroupRepository extends JpaRepository<SystemGroup, Long> {
+
+    @Query("FROM SystemGroup sg WHERE sg.latest = true AND sg.uuid = ?1")
+    SystemGroup findLatestByUuid(String uuid);
+
+    @Query("FROM SystemGroup sg WHERE sg.latest = true AND sg.deleted = false AND sg.mnemonic = ?1")
+    SystemGroup findLatestNotDeletedByMnemonic(String mnemonic);
+
+    @Query("FROM SystemGroup sg WHERE sg.latest = true AND sg.deleted = false AND sg.uuid = ?1")
+    SystemGroup findLatestNotDeletedByUuid(String uuid);
+
+    @Query("FROM SystemGroup sg WHERE sg.uuid = ?1")
+    List<SystemGroup> findByUuid(String uuid);
+
+    @Query("FROM SystemGroup sg WHERE sg.latest = true")
+    List<SystemGroup> findLatest();
+
+    @Query("FROM SystemGroup sg WHERE sg.latest = true AND sg.mnemonic = ?1")
+    List<SystemGroup> findLatestByMnemonic(String mnemonic);
+
+    @Query("FROM SystemGroup sg WHERE sg.latest = true AND sg.deleted = false")
+    List<SystemGroup> findLatestNotDeleted();
+
+}
diff --git a/src/main/java/org/openepics/names/repository/ISystemRepository.java b/src/main/java/org/openepics/names/repository/ISystemRepository.java
new file mode 100644
index 0000000..0933f2c
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/ISystemRepository.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository;
+
+import java.util.List;
+
+import org.openepics.names.repository.model.System;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Find system structure (name part) information from JPA.
+ *
+ * @author Lars Johansson
+ */
+@Repository
+public interface ISystemRepository extends JpaRepository<System, Long> {
+
+    @Query("FROM System sys WHERE sys.latest = true AND sys.uuid = ?1")
+    System findLatestByUuid(String uuid);
+
+    @Query("FROM System sys WHERE sys.latest = true AND sys.deleted = false AND sys.mnemonic = ?1")
+    System findLatestNotDeletedByMnemonic(String mnemonic);
+
+    @Query("FROM System sys WHERE sys.latest = true AND sys.deleted = false AND sys.uuid = ?1")
+    System findLatestNotDeletedByUuid(String uuid);
+
+    @Query("FROM System sys WHERE sys.latest = true AND sys.deleted = false AND sys.parent_uuid = ?1 and sys.mnemonic = ?2")
+    System findLatestNotDeletedByParentAndMnemonic(String uuid, String mnemonic);
+
+    @Query("FROM System sys WHERE sys.uuid = ?1")
+    List<System> findByUuid(String uuid);
+
+    @Query("FROM System sys WHERE sys.latest = true")
+    List<System> findLatest();
+
+    @Query("FROM System sys WHERE sys.latest = true AND sys.mnemonic = ?1")
+    List<System> findLatestByMnemonic(String mnemonic);
+
+    @Query("FROM System sys WHERE sys.latest = true AND sys.deleted = false")
+    List<System> findLatestNotDeleted();
+
+    @Query("FROM System sys WHERE sys.latest = true AND sys.deleted = false AND sys.parent_uuid = ?1")
+    List<System> findLatestNotDeletedByParent(String uuid);
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/DeviceGroup.java b/src/main/java/org/openepics/names/repository/model/DeviceGroup.java
new file mode 100644
index 0000000..6af57d0
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/DeviceGroup.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import java.util.UUID;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * This entity represents a device group name part.
+ *
+ * @author Lars Johansson
+ */
+@Entity
+@Table(name = "devicegroup")
+public class DeviceGroup extends Structure {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -8762287473417706804L;
+
+    private String parent_uuid;
+
+    public UUID getParentUuid() {
+        return parent_uuid != null ? UUID.fromString(parent_uuid) : null;
+    }
+    public void setParentUuid(UUID parent_uuid) {
+        this.parent_uuid = parent_uuid != null ? parent_uuid.toString() : null;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals ((DeviceGroup) obj);
+    }
+
+    public boolean equals(DeviceGroup other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        if (getParentUuid() == null) {
+            if (other.getParentUuid() != null)
+                return false;
+        } else if (!getParentUuid().equals(other.getParentUuid()))
+            return false;
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof DeviceGroup && ((DeviceGroup) other).getId().equals(getId());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                     + getId());
+        sb.append(", \"version\": "              + getVersion());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"parent_uuid\": "          + getParentUuid());
+        sb.append(", \"name\": "                 + getName());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"mnemonic_equivalence\": " + getMnemonicEquivalence());
+        sb.append(", \"description\": "          + getDescription());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append(", \"requested\": "            + getRequested());
+        sb.append(", \"requested_by\": "         + getRequestedBy());
+        sb.append(", \"requested_comment\": "    + getRequestedComment());
+        sb.append(", \"processed\": "            + getProcessed());
+        sb.append(", \"processed_by\": "         + getProcessedBy());
+        sb.append(", \"processed_comment\": "    + getProcessedComment());
+        sb.append("}");
+        return sb.toString();
+    }
+
+    public String toStringSimple() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": " + getId());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append("}");
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/DeviceType.java b/src/main/java/org/openepics/names/repository/model/DeviceType.java
new file mode 100644
index 0000000..74696b6
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/DeviceType.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import java.util.UUID;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * This entity represents a device type name part.
+ *
+ * @author Lars Johansson
+ */
+@Entity
+@Table(name = "devicetype")
+public class DeviceType extends Structure {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 2061731870402041740L;
+
+    private String parent_uuid;
+
+    public UUID getParentUuid() {
+        return parent_uuid != null ? UUID.fromString(parent_uuid) : null;
+    }
+    public void setParentUuid(UUID parent_uuid) {
+        this.parent_uuid = parent_uuid != null ? parent_uuid.toString() : null;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals ((DeviceType) obj);
+    }
+
+    public boolean equals(DeviceType other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        if (getParentUuid() == null) {
+            if (other.getParentUuid() != null)
+                return false;
+        } else if (!getParentUuid().equals(other.getParentUuid()))
+            return false;
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof DeviceType && ((DeviceType) other).getId().equals(getId());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                     + getId());
+        sb.append(", \"version\": "              + getVersion());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"parent_uuid\": "          + getParentUuid());
+        sb.append(", \"name\": "                 + getName());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"mnemonic_equivalence\": " + getMnemonicEquivalence());
+        sb.append(", \"description\": "          + getDescription());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append(", \"requested\": "            + getRequested());
+        sb.append(", \"requested_by\": "         + getRequestedBy());
+        sb.append(", \"requested_comment\": "    + getRequestedComment());
+        sb.append(", \"processed\": "            + getProcessed());
+        sb.append(", \"processed_by\": "         + getProcessedBy());
+        sb.append(", \"processed_comment\": "    + getProcessedComment());
+        sb.append("}");
+        return sb.toString();
+    }
+
+    public String toStringSimple() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": " + getId());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append("}");
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/Discipline.java b/src/main/java/org/openepics/names/repository/model/Discipline.java
new file mode 100644
index 0000000..6f98141
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/Discipline.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * This entity represents a discipline name part.
+ *
+ * @author Lars Johansson
+ */
+@Entity
+@Table(name = "discipline")
+public class Discipline extends Structure {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 8729921221024362502L;
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals ((Discipline) obj);
+    }
+
+    public boolean equals(Discipline other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof Discipline && ((Discipline) other).getId().equals(getId());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                     + getId());
+        sb.append(", \"version\": "              + getVersion());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"name\": "                 + getName());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"mnemonic_equivalence\": " + getMnemonicEquivalence());
+        sb.append(", \"description\": "          + getDescription());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append(", \"requested\": "            + getRequested());
+        sb.append(", \"requested_by\": "         + getRequestedBy());
+        sb.append(", \"requested_comment\": "    + getRequestedComment());
+        sb.append(", \"processed\": "            + getProcessed());
+        sb.append(", \"processed_by\": "         + getProcessedBy());
+        sb.append(", \"processed_comment\": "    + getProcessedComment());
+        sb.append("}");
+        return sb.toString();
+    }
+
+    public String toStringSimple() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": " + getId());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append("}");
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/Name.java b/src/main/java/org/openepics/names/repository/model/Name.java
new file mode 100644
index 0000000..749b185
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/Name.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * This entity represents a name.
+ *
+ * @author Lars Johansson
+ */
+@Entity
+@Table(name = "name")
+public class Name extends NameStructure implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 7313392211143183879L;
+
+    private String systemgroup_uuid;
+    private String system_uuid;
+    private String subsystem_uuid;
+    private String devicetype_uuid;
+    private String instance_index;
+    private String convention_name;
+    private String convention_name_equivalence;
+
+    public UUID getSystemgroupUuid() {
+        return systemgroup_uuid != null ? UUID.fromString(systemgroup_uuid) : null;
+    }
+    public void setSystemgroupUuid(UUID systemgroup_uuid) {
+        this.systemgroup_uuid = systemgroup_uuid != null ? systemgroup_uuid.toString() : null;
+    }
+    public UUID getSystemUuid() {
+        return system_uuid != null ? UUID.fromString(system_uuid) : null;
+    }
+    public void setSystemUuid(UUID system_uuid) {
+        this.system_uuid = system_uuid != null ? system_uuid.toString() : null;
+    }
+    public UUID getSubsystemUuid() {
+        return subsystem_uuid != null ? UUID.fromString(subsystem_uuid) : null;
+    }
+    public void setSubsystemUuid(UUID subsystem_uuid) {
+        this.subsystem_uuid = subsystem_uuid != null ? subsystem_uuid.toString() : null;
+    }
+    public UUID getDevicetypeUuid() {
+        return devicetype_uuid != null ? UUID.fromString(devicetype_uuid) : null;
+    }
+    public void setDevicetypeUuid(UUID devicetype_uuid) {
+        this.devicetype_uuid = devicetype_uuid != null ? devicetype_uuid.toString() : null;
+    }
+    public String getInstanceIndex() {
+        return instance_index;
+    }
+    public void setInstanceIndex(String instance_index) {
+        this.instance_index = instance_index;
+    }
+    public String getConventionName() {
+        return convention_name;
+    }
+    public void setConventionName(String convention_name) {
+        this.convention_name = convention_name;
+    }
+    public String getConventionNameEquivalence() {
+        return convention_name_equivalence;
+    }
+    public void setConventionNameEquivalence(String convention_name_equivalence) {
+        this.convention_name_equivalence = convention_name_equivalence;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals ((Name) obj);
+    }
+
+    public boolean equals(Name other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        if (getSystemgroupUuid() == null) {
+            if (other.getSystemgroupUuid() != null)
+                return false;
+        } else if (!getSystemgroupUuid().equals(other.getSystemgroupUuid()))
+            return false;
+        if (getSystemUuid() == null) {
+            if (other.getSystemUuid() != null)
+                return false;
+        } else if (!getSystemUuid().equals(other.getSystemUuid()))
+            return false;
+        if (getSubsystemUuid() == null) {
+            if (other.getSubsystemUuid() != null)
+                return false;
+        } else if (!getSubsystemUuid().equals(other.getSubsystemUuid()))
+            return false;
+        if (getDevicetypeUuid() == null) {
+            if (other.getDevicetypeUuid() != null)
+                return false;
+        } else if (!getDevicetypeUuid().equals(other.getDevicetypeUuid()))
+            return false;
+        if (getInstanceIndex() == null) {
+            if (other.getInstanceIndex() != null)
+                return false;
+        } else if (!getInstanceIndex().equals(other.getInstanceIndex()))
+            return false;
+        if (getConventionName() == null) {
+            if (other.getConventionName() != null)
+                return false;
+        } else if (!getConventionName().equals(other.getConventionName()))
+            return false;
+        if (getConventionNameEquivalence() == null) {
+            if (other.getConventionNameEquivalence() != null)
+                return false;
+        } else if (!getConventionNameEquivalence().equals(other.getConventionNameEquivalence()))
+            return false;
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof Name && ((Name) other).getId().equals(getId());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                            + getId());
+        sb.append(", \"version\": "                     + getVersion());
+        sb.append(", \"uuid\": "                        + getUuid());
+        sb.append(", \"systemgroup_uuid\": "            + getSystemgroupUuid());
+        sb.append(", \"system_uuid\": "                 + getSystemUuid());
+        sb.append(", \"subsystem_uuid\": "              + getSubsystemUuid());
+        sb.append(", \"devicetype_uuid\": "             + getDevicetypeUuid());
+        sb.append(", \"instance_index\": "              + getInstanceIndex());
+        sb.append(", \"convention_name\": "             + getConventionName());
+        sb.append(", \"convention_name_equivalence\": " + getConventionNameEquivalence());
+        sb.append(", \"description\": "                 + getDescription());
+        sb.append(", \"status\": "                      + getStatus());
+        sb.append(", \"latest\": "                      + isLatest());
+        sb.append(", \"deleted\": "                     + isDeleted());
+        sb.append(", \"requested\": "                   + getRequested());
+        sb.append(", \"requested_by\": "                + getRequestedBy());
+        sb.append(", \"requested_comment\": "           + getRequestedComment());
+        sb.append(", \"processed\": "                   + getProcessed());
+        sb.append(", \"processed_by\": "                + getProcessedBy());
+        sb.append(", \"processed_comment\": "           + getProcessedComment());
+        sb.append("}");
+        return sb.toString();
+    }
+
+    public String toStringSimple() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                            + getId());
+        sb.append(", \"uuid\": "                        + getUuid());
+        sb.append(", \"convention_name\": "             + getConventionName());
+        sb.append(", \"status\": "                      + getStatus());
+        sb.append(", \"latest\": "                      + isLatest());
+        sb.append(", \"deleted\": "                     + isDeleted());
+        sb.append("}");
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/NameStructure.java b/src/main/java/org/openepics/names/repository/model/NameStructure.java
new file mode 100644
index 0000000..88bd777
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/NameStructure.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Objects;
+import java.util.UUID;
+
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.MappedSuperclass;
+
+import org.openepics.names.rest.beans.Status;
+
+/**
+ * A superclass implementing properties required by JPA. It should be extended by
+ * name and structure classes that need to be persisted to the database.
+ *
+ * @author Lars Johansson
+ */
+@MappedSuperclass
+public class NameStructure extends Persistable implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 736094142259082938L;
+
+    private String uuid;
+    private String description;
+    @Enumerated(EnumType.STRING)
+    private Status status;
+    private Boolean latest;
+    private Boolean deleted;
+    private Date requested;
+    private String requested_by;
+    private String requested_comment;
+    private Date processed;
+    private String processed_by;
+    private String processed_comment;
+
+    public UUID getUuid() {
+        return uuid != null ? UUID.fromString(uuid) : null;
+    }
+    public void setUuid(UUID uuid) {
+        this.uuid = uuid != null ? uuid.toString() : null;
+    }
+    public String getDescription() {
+        return description;
+    }
+    public void setDescription(String description) {
+        this.description = description;
+    }
+    public Status getStatus() {
+        return status;
+    }
+    public void setStatus(Status status) {
+        this.status = status;
+    }
+    public Boolean isLatest() {
+        return latest;
+    }
+    public void setLatest(Boolean latest) {
+        this.latest = latest;
+    }
+    public Boolean isDeleted() {
+        return deleted;
+    }
+    public void setDeleted(Boolean deleted) {
+        this.deleted = deleted;
+    }
+    public Date getRequested() {
+        return requested;
+    }
+    public void setRequested(Date requested) {
+        this.requested = requested;
+    }
+    public String getRequestedBy() {
+        return requested_by;
+    }
+    public void setRequestedBy(String requested_by) {
+        this.requested_by = requested_by;
+    }
+    public String getRequestedComment() {
+        return requested_comment;
+    }
+    public void setRequestedComment(String requested_comment) {
+        this.requested_comment = requested_comment;
+    }
+    public Date getProcessed() {
+        return processed;
+    }
+    public void setProcessed(Date processed) {
+        this.processed = processed;
+    }
+    public String getProcessedBy() {
+        return processed_by;
+    }
+    public void setProcessedBy(String processed_by) {
+        this.processed_by = processed_by;
+    }
+    public String getProcessedComment() {
+        return processed_comment;
+    }
+    public void setProcessedComment(String processed_comment) {
+        this.processed_comment = processed_comment;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals((NameStructure) obj);
+    }
+
+    public boolean equals(NameStructure other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        if (getUuid() == null) {
+            if (other.getUuid() != null)
+                return false;
+        } else if (!getUuid().equals(other.getUuid()))
+            return false;
+        if (getDescription() == null) {
+            if (other.getDescription() != null)
+                return false;
+        } else if (!getDescription().equals(other.getDescription()))
+            return false;
+        if (getStatus() == null) {
+            if (other.getStatus() != null)
+                return false;
+        } else if (!getStatus().equals(other.getStatus()))
+            return false;
+        if (isLatest() == null) {
+            if (other.isLatest() != null)
+                return false;
+        } else if (!isLatest().equals(other.isLatest()))
+            return false;
+        if (isDeleted() == null) {
+            if (other.isDeleted() != null)
+                return false;
+        } else if (!isDeleted().equals(other.isDeleted()))
+            return false;
+        if (getRequested() == null) {
+            if (other.getRequested() != null)
+                return false;
+        } else if (!getRequested().equals(other.getRequested()))
+            return false;
+        if (getRequestedBy() == null) {
+            if (other.getRequestedBy() != null)
+                return false;
+        } else if (!getRequestedBy().equals(other.getRequestedBy()))
+            return false;
+        if (getRequestedComment() == null) {
+            if (other.getRequestedComment() != null)
+                return false;
+        } else if (!getRequestedComment().equals(other.getRequestedComment()))
+            return false;
+        if (getProcessed() == null) {
+            if (other.getProcessed() != null)
+                return false;
+        } else if (!getProcessed().equals(other.getProcessed()))
+            return false;
+        if (getProcessedBy() == null) {
+            if (other.getProcessedBy() != null)
+                return false;
+        } else if (!getProcessedBy().equals(other.getProcessedBy()))
+            return false;
+        if (getProcessedComment() == null) {
+            if (other.getProcessedComment() != null)
+                return false;
+        } else if (!getProcessedComment().equals(other.getProcessedComment()))
+            return false;
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof NameStructure && ((NameStructure) other).getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getUuid());
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/Persistable.java b/src/main/java/org/openepics/names/repository/model/Persistable.java
new file mode 100644
index 0000000..4c2370c
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/Persistable.java
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2014 European Spallation Source ERIC.
+ * Copyright (c) 2014 Cosylab d.d.
+ *
+ * This file is part of Naming Service.
+ * Naming Service is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 2 of the License, or any newer version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see https://www.gnu.org/licenses/gpl-2.0.txt
+ */
+
+package org.openepics.names.repository.model;
+
+import javax.annotation.Nullable;
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * A superclass implementing the properties required by JPA. It that should be extended by all classes that need to be
+ * persisted to the database.
+ *
+ * @author Marko Kolar
+ */
+@MappedSuperclass
+public class Persistable implements Serializable {
+
+    private static final long serialVersionUID = 8393161299438204843L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    protected @Nullable Long id;
+
+    @Version
+    private @Nullable Integer version;
+
+    /**
+     * The JPA entity ID.
+     * @return JPA entity id
+     */
+    public @Nullable Long getId() { return id; }
+
+    /**
+     * The JPA entity version.
+     * @return The JPA entity version
+     */
+    public @Nullable Integer getVersion() { return version; }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals((Persistable) obj);
+    }
+
+    public boolean equals(Persistable other) {
+        if (other == null)
+            return false;
+
+        if (id == null) {
+            if (other.id != null)
+                return false;
+        } else if (!id.equals(other.id))
+            return false;
+        if (version == null) {
+            if (other.version != null)
+                return false;
+        } else if (!version.equals(other.version))
+            return false;
+
+        return true;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/Structure.java b/src/main/java/org/openepics/names/repository/model/Structure.java
new file mode 100644
index 0000000..6f52654
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/Structure.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import java.io.Serializable;
+
+import javax.persistence.MappedSuperclass;
+
+/**
+ * A superclass implementing properties required by JPA. It should be extended by
+ * System structure and Device structure classes that need to be persisted to the database.
+ *
+ * @author Lars Johansson
+ */
+@MappedSuperclass
+public class Structure extends NameStructure implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -5980090194197159918L;
+
+    private String name;
+    private String mnemonic;
+    private String mnemonic_equivalence;
+
+    public String getName() {
+        return name;
+    }
+    public void setName(String name) {
+        this.name = name;
+    }
+    public String getMnemonic() {
+        return mnemonic;
+    }
+    public void setMnemonic(String mnemonic) {
+        this.mnemonic = mnemonic;
+    }
+    public String getMnemonicEquivalence() {
+        return mnemonic_equivalence;
+    }
+    public void setMnemonicEquivalence(String mnemonic_equivalence) {
+        this.mnemonic_equivalence = mnemonic_equivalence;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals((Structure) obj);
+    }
+
+    public boolean equals(Structure other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        if (getName() == null) {
+            if (other.getName() != null)
+                return false;
+        } else if (!getName().equals(other.getName()))
+            return false;
+        if (getMnemonic() == null) {
+            if (other.getMnemonic() != null)
+                return false;
+        } else if (!getMnemonic().equals(other.getMnemonic()))
+            return false;
+        if (getMnemonicEquivalence() == null) {
+            if (other.getMnemonicEquivalence() != null)
+                return false;
+        } else if (!getMnemonicEquivalence().equals(other.getMnemonicEquivalence()))
+            return false;
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof Structure && ((Structure) other).getId().equals(getId());
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/Subsystem.java b/src/main/java/org/openepics/names/repository/model/Subsystem.java
new file mode 100644
index 0000000..249c9ac
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/Subsystem.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import java.util.UUID;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * This entity represents a subsystem name part.
+ *
+ * @author Lars Johansson
+ */
+@Entity
+@Table(name = "subsystem")
+public class Subsystem extends Structure {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 5662135540008222500L;
+
+    private String parent_uuid;
+
+    public UUID getParentUuid() {
+        return parent_uuid != null ? UUID.fromString(parent_uuid) : null;
+    }
+    public void setParentUuid(UUID parent_uuid) {
+        this.parent_uuid = parent_uuid != null ? parent_uuid.toString() : null;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals ((Subsystem) obj);
+    }
+
+    public boolean equals(Subsystem other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        if (getParentUuid() == null) {
+            if (other.getParentUuid() != null)
+                return false;
+        } else if (!getParentUuid().equals(other.getParentUuid()))
+            return false;
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof Subsystem && ((Subsystem) other).getId().equals(getId());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                     + getId());
+        sb.append(", \"version\": "              + getVersion());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"parent_uuid\": "          + getParentUuid());
+        sb.append(", \"name\": "                 + getName());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"mnemonic_equivalence\": " + getMnemonicEquivalence());
+        sb.append(", \"description\": "          + getDescription());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append(", \"requested\": "            + getRequested());
+        sb.append(", \"requested_by\": "         + getRequestedBy());
+        sb.append(", \"requested_comment\": "    + getRequestedComment());
+        sb.append(", \"processed\": "            + getProcessed());
+        sb.append(", \"processed_by\": "         + getProcessedBy());
+        sb.append(", \"processed_comment\": "    + getProcessedComment());
+        sb.append("}");
+        return sb.toString();
+    }
+
+    public String toStringSimple() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": " + getId());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append("}");
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/System.java b/src/main/java/org/openepics/names/repository/model/System.java
new file mode 100644
index 0000000..221f7ae
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/System.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import java.util.UUID;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * This entity represents a system name part.
+ *
+ * @author Lars Johansson
+ */
+@Entity
+@Table(name = "system")
+public class System extends Structure {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -4323438470765348486L;
+
+    private String parent_uuid;
+
+    public UUID getParentUuid() {
+        return parent_uuid != null ? UUID.fromString(parent_uuid) : null;
+    }
+    public void setParentUuid(UUID parent_uuid) {
+        this.parent_uuid = parent_uuid != null ? parent_uuid.toString() : null;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals ((System) obj);
+    }
+
+    public boolean equals(System other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        if (getParentUuid() == null) {
+            if (other.getParentUuid() != null)
+                return false;
+        } else if (!getParentUuid().equals(other.getParentUuid()))
+            return false;
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof System && ((System) other).getId().equals(getId());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                     + getId());
+        sb.append(", \"version\": "              + getVersion());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"parent_uuid\": "          + getParentUuid());
+        sb.append(", \"name\": "                 + getName());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"mnemonic_equivalence\": " + getMnemonicEquivalence());
+        sb.append(", \"description\": "          + getDescription());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append(", \"requested\": "            + getRequested());
+        sb.append(", \"requested_by\": "         + getRequestedBy());
+        sb.append(", \"requested_comment\": "    + getRequestedComment());
+        sb.append(", \"processed\": "            + getProcessed());
+        sb.append(", \"processed_by\": "         + getProcessedBy());
+        sb.append(", \"processed_comment\": "    + getProcessedComment());
+        sb.append("}");
+        return sb.toString();
+    }
+
+    public String toStringSimple() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": " + getId());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append("}");
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/repository/model/SystemGroup.java b/src/main/java/org/openepics/names/repository/model/SystemGroup.java
new file mode 100644
index 0000000..c296257
--- /dev/null
+++ b/src/main/java/org/openepics/names/repository/model/SystemGroup.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.repository.model;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * This entity represents a system group name part.
+ *
+ * @author Lars Johansson
+ */
+@Entity
+@Table(name = "systemgroup")
+public class SystemGroup extends Structure {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 6298835206366539021L;
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        return equals ((SystemGroup) obj);
+    }
+
+    public boolean equals(SystemGroup other) {
+        if (other == null)
+            return false;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    public boolean equalsId(Object other) {
+        return other instanceof SystemGroup && ((SystemGroup) other).getId().equals(getId());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                     + getId());
+        sb.append(", \"version\": "              + getVersion());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"name\": "                 + getName());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"mnemonic_equivalence\": " + getMnemonicEquivalence());
+        sb.append(", \"description\": "          + getDescription());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append(", \"requested\": "            + getRequested());
+        sb.append(", \"requested_by\": "         + getRequestedBy());
+        sb.append(", \"requested_comment\": "    + getRequestedComment());
+        sb.append(", \"processed\": "            + getProcessed());
+        sb.append(", \"processed_by\": "         + getProcessedBy());
+        sb.append(", \"processed_comment\": "    + getProcessedComment());
+        sb.append("}");
+        return sb.toString();
+    }
+
+    public String toStringSimple() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{");
+        sb.append("\"id\": "                     + getId());
+        sb.append(", \"uuid\": "                 + getUuid());
+        sb.append(", \"mnemonic\": "             + getMnemonic());
+        sb.append(", \"status\": "               + getStatus());
+        sb.append(", \"latest\": "               + isLatest());
+        sb.append(", \"deleted\": "              + isDeleted());
+        sb.append("}");
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/beans/Status.java b/src/main/java/org/openepics/names/rest/beans/Status.java
new file mode 100644
index 0000000..72a67ea
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/beans/Status.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.beans;
+
+/**
+ * This enum represents status for names and structures data in beans and for communication.
+ *
+ * @author Lars Johansson
+ */
+public enum Status {
+
+    APPROVED,
+    ARCHIVED,
+    CANCELLED,
+    PENDING,
+    REJECTED;
+
+}
diff --git a/src/main/java/org/openepics/names/rest/beans/old/DeviceNameElement.java b/src/main/java/org/openepics/names/rest/beans/old/DeviceNameElement.java
new file mode 100644
index 0000000..1855661
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/beans/old/DeviceNameElement.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2014 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.beans.old;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import java.util.UUID;
+
+/**
+ * Data transfer object representing Devices for JSON and XML serialization.
+ *
+ * @author Andraz Pozar
+ * @author Banafsheh Hajinasab
+
+ */
+@XmlRootElement
+public class DeviceNameElement {
+
+    private UUID uuid;
+    private String systemGroup;
+    private String system;
+    private String subsystem;
+    private String discipline;
+    private String deviceType;
+    private String instanceIndex;
+    private String name;
+    private String description;
+    private String status;
+
+    /**
+     * Constructor.
+     */
+    public DeviceNameElement() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param uuid      the unique uuid of the name that this element is accociated with.
+     * @param name      the naming convention name
+     * @param status    of the name Element. DELETED if the name associated with this uuid has been deleted.
+     *                  ACTIVE if the name element is not delted and is the  most recent name element for this uuid.
+     *                  OBSOLETE if the name element is neither deleted nor active
+     *                  (i.e. there exists a newer version for the same uuid..)
+     */
+    public DeviceNameElement(UUID uuid, String name, String status) {
+        this.uuid = uuid;
+        this.name = name;
+        this.status = status;
+    }
+
+    /**
+     * @return the uuid
+     */
+    public UUID getUuid() {
+        return uuid;
+    }
+
+    /**
+     * @param uuid the uuid to set
+     */
+    public void setUuid(UUID uuid) {
+        this.uuid = uuid;
+    }
+
+    /**
+     * @return the systemGroup
+     */
+    public String getSystemGroup() {
+        return systemGroup;
+    }
+
+    /**
+     * @param systemGroup the systemGroup to set
+     */
+    public void setSystemGroup(String systemGroup) {
+        this.systemGroup = systemGroup;
+    }
+
+    /**
+     * @return the system
+     */
+    public String getSystem() {
+        return system;
+    }
+
+    /**
+     * @param system the system to set
+     */
+    public void setSystem(String system) {
+        this.system = system;
+    }
+
+    /**
+     * @return the subsystem
+     */
+    public String getSubsystem() {
+        return subsystem;
+    }
+
+    /**
+     * @param subsystem the subsystem to set
+     */
+    public void setSubsystem(String subsystem) {
+        this.subsystem = subsystem;
+    }
+
+    /**
+     * @return the discipline
+     */
+    public String getDiscipline() {
+        return discipline;
+    }
+
+    /**
+     * @param discipline the discipline to set
+     */
+    public void setDiscipline(String discipline) {
+        this.discipline = discipline;
+    }
+
+    /**
+     * @return the deviceType
+     */
+    public String getDeviceType() {
+        return deviceType;
+    }
+
+    /**
+     * @param deviceType the deviceType to set
+     */
+    public void setDeviceType(String deviceType) {
+        this.deviceType = deviceType;
+    }
+
+    /**
+     * @return the instanceIndex
+     */
+    public String getInstanceIndex() {
+        return instanceIndex;
+    }
+
+    /**
+     * @param instanceIndex the instanceIndex to set
+     */
+    public void setInstanceIndex(String instanceIndex) {
+        this.instanceIndex = instanceIndex;
+    }
+
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * @param description the description to set
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * @return the status
+     */
+    public String getStatus() {
+        return status;
+    }
+
+    /**
+     * @param status the status to set
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/beans/old/HistoryElement.java b/src/main/java/org/openepics/names/rest/beans/old/HistoryElement.java
new file mode 100644
index 0000000..ac4cba9
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/beans/old/HistoryElement.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.beans.old;
+
+import java.util.UUID;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Data transfer object representing history of name elements for JSON and XML serialization.
+ *
+ * @author Lars Johansson
+ */
+@XmlRootElement
+public class HistoryElement {
+
+    private UUID uuid;
+    private String fullName;
+    private String mnemonic;
+    private String description;
+    private String status;
+    private String date;
+    private String user;
+    private String message;
+
+    /**
+     * Constructor.
+     */
+    public HistoryElement() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param uuid           uuid
+     * @param fullName       naming convention name
+     * @param mnemonic       mnemonic
+     * @param description    description
+     * @param status         status
+     * @param date           date
+     * @param user           user
+     * @param message        message
+     */
+    public HistoryElement(UUID uuid, String fullName, String mnemonic, String description, String status,
+            String date, String user, String message) {
+        super();
+        this.uuid = uuid;
+        this.fullName = fullName;
+        this.mnemonic = mnemonic;
+        this.description = description;
+        this.status = status;
+        this.date = date;
+        this.user = user;
+        this.message = message;
+    }
+
+    /**
+     * @return the uuid
+     */
+    public UUID getUuid() {
+        return uuid;
+    }
+    /**
+     * @param uuid the uuid to set
+     */
+    public void setUuid(UUID uuid) {
+        this.uuid = uuid;
+    }
+    /**
+     * @return the fullName
+     */
+    public String getFullName() {
+        return fullName;
+    }
+    /**
+     * @param fullName the fullName to set
+     */
+    public void setFullName(String fullName) {
+        this.fullName = fullName;
+    }
+    /**
+     * @return the mnemonic
+     */
+    public String getMnemonic() {
+        return mnemonic;
+    }
+    /**
+     * @param mnemonic the mnemonic to set
+     */
+    public void setMnemonic(String mnemonic) {
+        this.mnemonic = mnemonic;
+    }
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+    /**
+     * @param description the description to set
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+    /**
+     * @return the status
+     */
+    public String getStatus() {
+        return status;
+    }
+    /**
+     * @param status the status to set
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+    /**
+     * @return the date
+     */
+    public String getDate() {
+        return date;
+    }
+    /**
+     * @param date the date to set
+     */
+    public void setDate(String date) {
+        this.date = date;
+    }
+    /**
+     * @return the user
+     */
+    public String getUser() {
+        return user;
+    }
+    /**
+     * @param user the user to set
+     */
+    public void setUser(String user) {
+        this.user = user;
+    }
+    /**
+     * @return the message
+     */
+    public String getMessage() {
+        return message;
+    }
+    /**
+     * @param message the message to set
+     */
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/beans/old/PartElement.java b/src/main/java/org/openepics/names/rest/beans/old/PartElement.java
new file mode 100644
index 0000000..b6d191b
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/beans/old/PartElement.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2020 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.beans.old;
+
+import java.util.UUID;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Data transfer object representing name parts for JSON and XML serialization.
+ * Intended usage is for System Structure and Device Structure.
+ *
+ * @author Lars Johansson
+ */
+@XmlRootElement
+public class PartElement {
+
+    private String type;
+    private UUID uuid;
+    private String name;
+    private String namePath;
+    private String mnemonic;
+    private String mnemonicPath;
+    private String level;
+    private String description;
+    private String status;
+
+    /**
+     * Constructor.
+     */
+    public PartElement() {
+        super();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param type the type
+     * @param uuid the uuid
+     * @param name the name
+     * @param namePath the name path
+     * @param mnemonic the mnemonic
+     * @param mnemonicPath the mnemonic path
+     * @param level the level
+     * @param description the description
+     * @param status the status
+     */
+    public PartElement(String type, UUID uuid,
+            String name, String namePath, String mnemonic, String mnemonicPath, String level,
+            String description, String status) {
+        super();
+        this.type = type;
+        this.uuid = uuid;
+        this.name = name;
+        this.namePath = namePath;
+        this.mnemonic = mnemonic;
+        this.mnemonicPath = mnemonicPath;
+        this.level = level;
+        this.description = description;
+        this.status = status;
+    }
+
+    /**
+     * @return the type
+     */
+    public String getType() {
+        return type;
+    }
+    /**
+     * @param type the type to set
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+    /**
+     * @return the uuid
+     */
+    public UUID getUuid() {
+        return uuid;
+    }
+    /**
+     * @param uuid the uuid to set
+     */
+    public void setUuid(UUID uuid) {
+        this.uuid = uuid;
+    }
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+    /**
+     * @return the name path
+     */
+    public String getNamePath() {
+        return namePath;
+    }
+    /**
+     * @param mnemonicPath the name path to set
+     */
+    public void setNamePath(String namePath) {
+        this.namePath = namePath;
+    }
+    /**
+     * @return the mnemonic
+     */
+    public String getMnemonic() {
+        return mnemonic;
+    }
+    /**
+     * @param mnemonic the mnemonic to set
+     */
+    public void setMnemonic(String mnemonic) {
+        this.mnemonic = mnemonic;
+    }
+    /**
+     * @return the mnemonic path
+     */
+    public String getMnemonicPath() {
+        return mnemonicPath;
+    }
+    /**
+     * @param mnemonicPath the mnemonic path to set
+     */
+    public void setMnemonicPath(String mnemonicPath) {
+        this.mnemonicPath = mnemonicPath;
+    }
+    /**
+     * @return the level
+     */
+    public String getLevel() {
+        return level;
+    }
+    /**
+     * @param level the level to set
+     */
+    public void setLevel(String level) {
+        this.level = level;
+    }
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+    /**
+     * @param description the description to set
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+    /**
+     * @return the status
+     */
+    public String getStatus() {
+        return status;
+    }
+    /**
+     * @param status the status to set
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/controller/old/DeviceNamesControllerV0.java b/src/main/java/org/openepics/names/rest/controller/old/DeviceNamesControllerV0.java
new file mode 100644
index 0000000..e1bfa17
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/controller/old/DeviceNamesControllerV0.java
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.controller.old;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.openepics.names.repository.IDeviceGroupRepository;
+import org.openepics.names.repository.IDeviceTypeRepository;
+import org.openepics.names.repository.IDisciplineRepository;
+import org.openepics.names.repository.INameRepository;
+import org.openepics.names.repository.ISubsystemRepository;
+import org.openepics.names.repository.ISystemGroupRepository;
+import org.openepics.names.repository.ISystemRepository;
+import org.openepics.names.repository.model.Name;
+import org.openepics.names.rest.beans.old.DeviceNameElement;
+import org.openepics.names.util.HolderIRepositories;
+import org.openepics.names.util.HolderSystemDeviceStructure;
+import org.openepics.names.util.NamingConventionUtil;
+import org.openepics.names.util.old.DeviceNameElementUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.google.common.collect.Lists;
+
+/**
+ * This part of REST API provides device name data for Naming application.
+ *
+ * @author Lars Johansson
+ */
+@RestController
+@RequestMapping("/rest/deviceNames")
+@EnableAutoConfiguration
+public class DeviceNamesControllerV0 {
+
+    // note
+    //     global exception handler available
+
+    /*
+       Methods
+           read      GET /deviceNames                                - findNames()
+           read      GET /deviceNames/search/{name}                  - findNamesSearch(String)
+           read      GET /deviceNames/system/{system}                - findNamesBySystem(String)
+           read      GET /deviceNames/system/search/{system}         - findNamesBySystemSearch(String)
+           read      GET /deviceNames/subsystem/{subsystem}          - findNamesBySubsystem(String)
+           read      GET /deviceNames/subsystem/search/{subsystem}   - findNamesBySubsystemSearch(String)
+           read      GET /deviceNames/discipline/{discipline}        - findNamesByDiscipline(String)
+           read      GET /deviceNames/discipline/search/{discipline} - findNamesByDisciplineSearch(String)
+           read      GET /deviceNames/devicetype/{devicetype}        - findNamesByDeviceType(String)
+           read      GET /deviceNames/devicetype/search/{devicetype} - findNamesByDeviceTypeSearch(String)
+           read      GET /deviceNames/{uuid}                         - findName(String) (uuid or name)
+     */
+
+    private static final Logger LOGGER = Logger.getLogger(DeviceNamesControllerV0.class.getName());
+
+    private HolderIRepositories holderIRepositories;
+
+    @Autowired
+    public DeviceNamesControllerV0(
+            INameRepository iNameRepository,
+            ISystemGroupRepository iSystemGroupRepository,
+            ISystemRepository iSystemRepository,
+            ISubsystemRepository iSubsystemRepository,
+            IDisciplineRepository iDisciplineRepository,
+            IDeviceGroupRepository iDeviceGroupRepository,
+            IDeviceTypeRepository iDeviceTypeRepository) {
+
+        holderIRepositories = new HolderIRepositories(
+                iNameRepository,
+                iSystemGroupRepository,
+                iSystemRepository,
+                iSubsystemRepository,
+                iDisciplineRepository,
+                iDeviceGroupRepository,
+                iDeviceTypeRepository);
+    }
+
+    /**
+     * Find valid names.
+     *
+     * @return all valid names
+     */
+    @GetMapping
+    public List<DeviceNameElement> findNames() {
+        List<Name> names = holderIRepositories.getNameRepository().findLatestNotDeleted();
+
+        // create collection with known initial capacity
+        final List<DeviceNameElement> deviceNameElements = new ArrayList<>(names.size());
+
+        // initiate holder of containers for system and device structure content, for performance reasons
+        HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+        for (Name name : names) {
+            deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+        }
+
+        LOGGER.log(Level.INFO, "findNames, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by name search.
+     * <br/>
+     * Note
+     * <ul>
+     * <li>name (search, case sensitive, regex)
+     * <li>search done for all parts of name
+     * </ul>
+     *
+     * @param name name to search for
+     * @return a list of names
+     */
+    @GetMapping("/search/{name}")
+    public List<DeviceNameElement> findNamesSearch(@PathVariable("name") String name) {
+        // note
+        //     search
+        //     case sensitive
+        //     regex
+
+        final List<DeviceNameElement> deviceNameElements = Lists.newArrayList();
+        Pattern pattern = null;
+        try {
+            pattern = Pattern.compile(name);
+        } catch (PatternSyntaxException e) {
+            LOGGER.log(Level.FINE, e.getMessage(), e);
+            return deviceNameElements;
+        }
+
+        List<Name> names = holderIRepositories.getNameRepository().findLatestNotDeleted();
+
+        // initiate holder of containers for system and device structure content, for performance reasons
+        HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+        for (Name namee : names) {
+            if (pattern.matcher(namee.getConventionName()).find()) {
+                deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(namee, holder));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamesSearch, name:                    " + name);
+        LOGGER.log(Level.INFO, "findNamesSearch, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by system.
+     * Note system (exact match, case sensitive).
+     *
+     * @param system system to look for
+     * @return a list of names
+     */
+    @GetMapping("/system/{system}")
+    public List<DeviceNameElement> findNamesBySystem(@PathVariable("system") String system) {
+        // note
+        //     exact match
+        //     case sensitive
+
+        // initiate holder of containers for system and device structure content, for performance reasons
+        HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+        final List<DeviceNameElement> deviceNameElements = Lists.newArrayList();
+        List<Name> namesSystemGroup            = holderIRepositories.getNameRepository().findLatestBySystemGroupMnemonic(system);
+        for (Name name : namesSystemGroup) {
+            deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+        }
+        List<Name> namesSystem                 = holderIRepositories.getNameRepository().findLatestBySystemMnemonic(system);
+        List<Name> namesSystemThroughSubsystem = holderIRepositories.getNameRepository().findLatestBySystemMnemonicThroughSubsystem(system);
+        for (Name name : namesSystem) {
+            deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+        }
+        for (Name name : namesSystemThroughSubsystem) {
+            deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+        }
+
+        LOGGER.log(Level.INFO, "findNamesBySystem, system:                  " + system);
+        LOGGER.log(Level.INFO, "findNamesBySystem, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by system search.
+     * Note system (search, case sensitive, regex).
+     *
+     * @param system system to search for
+     * @return a list of names
+     */
+    @GetMapping("/system/search/{system}")
+    public List<DeviceNameElement> findNamesBySystemSearch(@PathVariable("system") String system) {
+        // note
+        //     search
+        //     case sensitive
+        //     regex
+
+        final List<DeviceNameElement> deviceNameElements = Lists.newArrayList();
+        Pattern pattern = null;
+        try {
+            pattern = Pattern.compile(system);
+        } catch (PatternSyntaxException e) {
+            LOGGER.log(Level.FINE, e.getMessage(), e);
+            return deviceNameElements;
+        }
+
+        List<Name> names = holderIRepositories.getNameRepository().findLatestNotDeleted();
+
+        // initiate holder of containers for system and device structure content, for performance reasons
+        HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+        for (Name name : names) {
+            String sub = NamingConventionUtil.extractSystem(name.getConventionName());
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamesSearch, system:                  " + system);
+        LOGGER.log(Level.INFO, "findNamesSearch, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by subsystem.
+     * Note subsystem (exact match, case sensitive).
+     *
+     * @param subsystem subsystem to look for
+     * @return a list of names
+     */
+    @GetMapping("/subsystem/{subsystem}")
+    public List<DeviceNameElement> findNamesBySubsystem(@PathVariable("subsystem") String subsystem) {
+        // note
+        //     exact match
+        //     case sensitive
+
+        List<Name> names = holderIRepositories.getNameRepository().findLatestBySubsystemMnemonic(subsystem);
+
+        // create collection with known initial capacity
+        final List<DeviceNameElement> deviceNameElements = new ArrayList<>(names.size());
+
+        if (!names.isEmpty()) {
+            // initiate holder of containers for system and device structure content, for performance reasons
+            HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+            for (Name name : names) {
+                deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamesBySubsystem, subsystem:               " + subsystem);
+        LOGGER.log(Level.INFO, "findNamesBySubsystem, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by subsystem search.
+     * Note subsystem (search, case sensitive, regex).
+     *
+     * @param subsystem subsystem to search for
+     * @return a list of names
+     */
+    @GetMapping("/subsystem/search/{subsystem}")
+    public List<DeviceNameElement> findNamesBySubsystemSearch(@PathVariable("subsystem") String subsystem) {
+        // note
+        //     search
+        //     case sensitive
+        //     regex
+
+        final List<DeviceNameElement> deviceNameElements = Lists.newArrayList();
+        Pattern pattern = null;
+        try {
+            pattern = Pattern.compile(subsystem);
+        } catch (PatternSyntaxException e) {
+            LOGGER.log(Level.FINE, e.getMessage(), e);
+            return deviceNameElements;
+        }
+
+        List<Name> names = holderIRepositories.getNameRepository().findLatestNotDeleted();
+
+        // initiate holder of containers for system and device structure content, for performance reasons
+        HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+        for (Name name : names) {
+            String sub = NamingConventionUtil.extractSubsystem(name.getConventionName());
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamesBySubsystemSearch, subsystem:               " + subsystem);
+        LOGGER.log(Level.INFO, "findNamesBySubsystemSearch, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by discipline.
+     * Note discipline (exact match, case sensitive).
+     *
+     * @param discipline discipline to look for
+     * @return a list of names
+     */
+    @GetMapping("/discipline/{discipline}")
+    public List<DeviceNameElement> findNamesByDiscipline(@PathVariable("discipline") String discipline) {
+        // note
+        //     exact match
+        //     case sensitive
+
+        List<Name> names = holderIRepositories.getNameRepository().findLatestByDisciplineMnemonic(discipline);
+
+        // create collection with known initial capacity
+        final List<DeviceNameElement> deviceNameElements = new ArrayList<>(names.size());
+
+        if (!names.isEmpty()) {
+            // initiate holder of containers for system and device structure content, for performance reasons
+            HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+            for (Name name : names) {
+                deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamesByDiscipline, discipline:              " + discipline);
+        LOGGER.log(Level.INFO, "findNamesByDiscipline, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by discipline search.
+     * Note discipline (search, case sensitive, regex).
+     *
+     * @param discipline discipline to search for
+     * @return a list of names
+     */
+    @GetMapping("/discipline/search/{discipline}")
+    public List<DeviceNameElement> findNamesByDisciplineSearch(@PathVariable("discipline") String discipline) {
+        // note
+        //     search
+        //     case sensitive
+        //     regex
+
+        final List<DeviceNameElement> deviceNameElements = Lists.newArrayList();
+        Pattern pattern = null;
+        try {
+            pattern = Pattern.compile(discipline);
+        } catch (PatternSyntaxException e) {
+            LOGGER.log(Level.FINE, e.getMessage(), e);
+            return deviceNameElements;
+        }
+
+        List<Name> names = holderIRepositories.getNameRepository().findLatestNotDeleted();
+
+        // initiate holder of containers for system and device structure content, for performance reasons
+        HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+        for (Name name : names) {
+            String sub = NamingConventionUtil.extractDiscipline(name.getConventionName());
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamesByDisciplineSearch, discipline:              " + discipline);
+        LOGGER.log(Level.INFO, "findNamesByDisciplineSearch, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by device type.
+     * Note device type (exact match, case sensitive).
+     *
+     * @param deviceType device type to look for
+     * @return a list of names
+     */
+    @GetMapping("/devicetype/{devicetype}")
+    public List<DeviceNameElement> findNamesByDeviceType(@PathVariable("devicetype") String deviceType) {
+        // note
+        //     exact match
+        //     case sensitive
+
+        List<Name> names = holderIRepositories.getNameRepository().findLatestByDeviceTypeMnemonic(deviceType);
+
+        // create collection with known initial capacity
+        final List<DeviceNameElement> deviceNameElements = new ArrayList<>(names.size());
+
+        if (!names.isEmpty()) {
+            // initiate holder of containers for system and device structure content, for performance reasons
+            HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+            for (Name name : names) {
+                deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamesByDeviceType, deviceType:              " + deviceType);
+        LOGGER.log(Level.INFO, "findNamesByDeviceType, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find names by device type search.
+     * Note device type (search, case sensitive, regex).
+     *
+     * @param deviceType device type to search for
+     * @return a list of names
+     */
+    @GetMapping("/devicetype/search/{devicetype}")
+    public List<DeviceNameElement> findNamesByDeviceTypeSearch(@PathVariable("devicetype") String deviceType) {
+        // note
+        //     search
+        //     case sensitive
+        //     regex
+
+        final List<DeviceNameElement> deviceNameElements = Lists.newArrayList();
+        Pattern pattern = null;
+        try {
+            pattern = Pattern.compile(deviceType);
+        } catch (PatternSyntaxException e) {
+            LOGGER.log(Level.FINE, e.getMessage(), e);
+            return deviceNameElements;
+        }
+
+        List<Name> names = holderIRepositories.getNameRepository().findLatestNotDeleted();
+
+        // initiate holder of containers for system and device structure content, for performance reasons
+        HolderSystemDeviceStructure holder = new HolderSystemDeviceStructure(holderIRepositories);
+
+        for (Name name : names) {
+            String sub = NamingConventionUtil.extractDeviceType(name.getConventionName());
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                deviceNameElements.add(DeviceNameElementUtil.getDeviceNameElement(name, holder));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamesByDeviceTypeSearch, deviceType:              " + deviceType);
+        LOGGER.log(Level.INFO, "findNamesByDeviceTypeSearch, deviceNameElements.size: " + deviceNameElements.size());
+
+        return deviceNameElements;
+    }
+
+    /**
+     * Find name by uuid or name (exact match, case sensitive).
+     *
+     * @param uuid string uuid or device name
+     * @return name (most recent)
+     */
+    @GetMapping("/{uuid}")
+    public DeviceNameElement findName(@PathVariable("uuid") String uuid) {
+        // note
+        //     exact match
+        //     case sensitive
+
+        Name name = null;
+        try {
+            UUID.fromString(uuid);
+            name = holderIRepositories.getNameRepository().findLatestByUuid(uuid);
+        } catch (IllegalArgumentException e) {
+            name = holderIRepositories.getNameRepository().findLatestByConventionName(uuid);
+        }
+        DeviceNameElement deviceNameElement = DeviceNameElementUtil.getDeviceNameElement(name, holderIRepositories);
+
+        LOGGER.log(Level.INFO, "findName, uuid:              " + uuid);
+        LOGGER.log(Level.INFO, "findName, deviceNameElement: " + deviceNameElement);
+
+        return deviceNameElement;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/controller/old/HealthcheckControllerV0.java b/src/main/java/org/openepics/names/rest/controller/old/HealthcheckControllerV0.java
new file mode 100644
index 0000000..94606e6
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/controller/old/HealthcheckControllerV0.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.controller.old;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * This part of REST API provides healthcheck of Naming application.
+ *
+ * @author Lars Johansson
+ */
+@RestController
+@RequestMapping("/rest/healthcheck")
+@EnableAutoConfiguration
+public class HealthcheckControllerV0 {
+
+    // note
+    //     global exception handler available
+
+    /*
+       Methods
+           read      GET /healthcheck - healthcheck()
+     */
+
+    /**
+     * Perform healthcheck of Naming application in general and healtcheck endpoint in particular.
+     * To be used mainly for checking HTTP response code, in particular HTTP STATUS OK - 200.
+     *
+     * @return server timestamp
+     */
+    @GetMapping
+    public String healthcheck() {
+        // return healthcheck as server timestamp
+        //     datetime - dateStyle, timeStyle - full
+
+        return SimpleDateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date());
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/controller/old/HistoryControllerV0.java b/src/main/java/org/openepics/names/rest/controller/old/HistoryControllerV0.java
new file mode 100644
index 0000000..9ec01d7
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/controller/old/HistoryControllerV0.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.controller.old;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.lang3.StringUtils;
+import org.openepics.names.repository.IDeviceGroupRepository;
+import org.openepics.names.repository.IDeviceTypeRepository;
+import org.openepics.names.repository.IDisciplineRepository;
+import org.openepics.names.repository.INameRepository;
+import org.openepics.names.repository.ISubsystemRepository;
+import org.openepics.names.repository.ISystemGroupRepository;
+import org.openepics.names.repository.ISystemRepository;
+import org.openepics.names.repository.model.DeviceGroup;
+import org.openepics.names.repository.model.DeviceType;
+import org.openepics.names.repository.model.Discipline;
+import org.openepics.names.repository.model.Name;
+import org.openepics.names.repository.model.Subsystem;
+import org.openepics.names.repository.model.System;
+import org.openepics.names.repository.model.SystemGroup;
+import org.openepics.names.rest.beans.old.HistoryElement;
+import org.openepics.names.util.HolderIRepositories;
+import org.openepics.names.util.old.HistoryElementUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.google.common.collect.Lists;
+
+/**
+ * This part of REST API provides history for names and name part data for Naming application.
+ *
+ * @author Lars Johansson
+ */
+@RestController
+@RequestMapping("/rest/history")
+@EnableAutoConfiguration
+public class HistoryControllerV0 {
+
+    // note
+    //     global exception handler available
+
+    /*
+       Methods
+           read      GET /history/parts/uuid/{uuid}       - findNamePartHistoryForUuid(String)
+           read      GET /history/deviceNames/uuid/{uuid} - findNameHistoryForUuid(String)
+     */
+
+    private static final Logger LOGGER = Logger.getLogger(HistoryControllerV0.class.getName());
+
+    private static final long THOUSAND_MILLISECONDS = 1000;
+
+    private HolderIRepositories holderIRepositories;
+
+    @Autowired
+    public HistoryControllerV0(
+            INameRepository iNameRepository,
+            ISystemGroupRepository iSystemGroupRepository,
+            ISystemRepository iSystemRepository,
+            ISubsystemRepository iSubsystemRepository,
+            IDisciplineRepository iDisciplineRepository,
+            IDeviceGroupRepository iDeviceGroupRepository,
+            IDeviceTypeRepository iDeviceTypeRepository) {
+
+        holderIRepositories = new HolderIRepositories(
+                iNameRepository,
+                iSystemGroupRepository,
+                iSystemRepository,
+                iSubsystemRepository,
+                iDisciplineRepository,
+                iDeviceGroupRepository,
+                iDeviceTypeRepository);
+    }
+
+    /**
+     * Find history for name part by uuid.
+     * Note uuid (exact match).
+     *
+     * @param uuid uuid to look for
+     * @return a list of entries for history of name part
+     */
+    @GetMapping("/parts/uuid/{uuid}")
+    public List<HistoryElement> findNamePartHistoryForUuid(@PathVariable("uuid") String uuid) {
+        // check parameters
+        // prepare retrieval of information
+        // retrieve information
+        // prepare return elements
+
+        boolean hasUuid = !StringUtils.isEmpty(uuid);
+
+        final List<HistoryElement> historyElements = Lists.newArrayList();
+        if (!hasUuid) {
+            return historyElements;
+        }
+
+        List<SystemGroup> systemGroups = holderIRepositories.getSystemGroupRepository().findByUuid(uuid);
+        List<System>      systems      = holderIRepositories.getSystemRepository().findByUuid(uuid);
+        List<Subsystem>   subsystems   = holderIRepositories.getSubsystemRepository().findByUuid(uuid);
+
+        List<Discipline>  disciplines  = holderIRepositories.getDisciplineRepository().findByUuid(uuid);
+        List<DeviceGroup> deviceGroups = holderIRepositories.getDeviceGroupRepository().findByUuid(uuid);
+        List<DeviceType>  deviceTypes  = holderIRepositories.getDeviceTypeRepository().findByUuid(uuid);
+
+        if (!systemGroups.isEmpty()) {
+            for (SystemGroup systemGroup : systemGroups) {
+                // one or two return elements
+                //     processed != null and processed != requested (>  1s difference) --> two entries (processed, requested)
+                //     processed != null and processed == requested (<= 1s difference) --> one entry   (processed initial)
+                //     processed == null                                               --> one entry   (requested)
+
+                if (systemGroup.getProcessed() != null && ((systemGroup.getProcessed().getTime() - systemGroup.getRequested().getTime()) > THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(systemGroup));
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(systemGroup));
+                } else if (systemGroup.getProcessed() != null && ((systemGroup.getProcessed().getTime() - systemGroup.getRequested().getTime()) <= THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(systemGroup));
+                } else {
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(systemGroup));
+                }
+            }
+        } else if (!systems.isEmpty()) {
+            for (System system : systems) {
+                // one or two return elements
+                //     processed != null and processed != requested (>  1s difference) --> two entries (processed, requested)
+                //     processed != null and processed == requested (<= 1s difference) --> one entry   (processed initial)
+                //     processed == null                                               --> one entry   (requested)
+
+                if (system.getProcessed() != null && ((system.getProcessed().getTime() - system.getRequested().getTime()) > THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(system));
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(system));
+                } else if (system.getProcessed() != null && ((system.getProcessed().getTime() - system.getRequested().getTime()) <= THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(system));
+                } else {
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(system));
+                }
+            }
+        } else if (!subsystems.isEmpty()) {
+            for (Subsystem subsystem : subsystems) {
+                // one or two return elements
+                //     processed != null and processed != requested (>  1s difference) --> two entries (processed, requested)
+                //     processed != null and processed == requested (<= 1s difference) --> one entry   (processed initial)
+                //     processed == null                                               --> one entry   (requested)
+
+                if (subsystem.getProcessed() != null && ((subsystem.getProcessed().getTime() - subsystem.getRequested().getTime()) > THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(subsystem));
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(subsystem));
+                } else if (subsystem.getProcessed() != null && ((subsystem.getProcessed().getTime() - subsystem.getRequested().getTime()) <= THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(subsystem));
+                } else {
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(subsystem));
+                }
+            }
+        } else if (!disciplines.isEmpty()) {
+            for (Discipline discipline : disciplines) {
+                // one or two return elements
+                //     processed != null and processed != requested (>  1s difference) --> two entries (processed, requested)
+                //     processed != null and processed == requested (<= 1s difference) --> one entry   (processed initial)
+                //     processed == null                                               --> one entry   (requested)
+
+                if (discipline.getProcessed() != null && ((discipline.getProcessed().getTime() - discipline.getRequested().getTime()) > THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(discipline));
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(discipline));
+                } else if (discipline.getProcessed() != null && ((discipline.getProcessed().getTime() - discipline.getRequested().getTime()) <= THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(discipline));
+                } else {
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(discipline));
+                }
+            }
+        } else if (!deviceGroups.isEmpty()) {
+            for (DeviceGroup deviceGroup : deviceGroups) {
+                // one or two return elements
+                //     processed != null and processed != requested (>  1s difference) --> two entries (processed, requested)
+                //     processed != null and processed == requested (<= 1s difference) --> one entry   (processed initial)
+                //     processed == null                                               --> one entry   (requested)
+
+                if (deviceGroup.getProcessed() != null && ((deviceGroup.getProcessed().getTime() - deviceGroup.getRequested().getTime()) > THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(deviceGroup));
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(deviceGroup));
+                } else if (deviceGroup.getProcessed() != null && ((deviceGroup.getProcessed().getTime() - deviceGroup.getRequested().getTime()) <= THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(deviceGroup));
+                } else {
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(deviceGroup));
+                }
+            }
+        } else if (!deviceTypes.isEmpty()) {
+            for (DeviceType deviceType : deviceTypes) {
+                // one or two return elements
+                //     processed != null and processed != requested (>  1s difference) --> two entries (processed, requested)
+                //     processed != null and processed == requested (<= 1s difference) --> one entry   (processed initial)
+                //     processed == null                                               --> one entry   (requested)
+
+                if (deviceType.getProcessed() != null && ((deviceType.getProcessed().getTime() - deviceType.getRequested().getTime()) > THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(deviceType));
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(deviceType));
+                } else if (deviceType.getProcessed() != null && ((deviceType.getProcessed().getTime() - deviceType.getRequested().getTime()) <= THOUSAND_MILLISECONDS)) {
+                    historyElements.add(HistoryElementUtil.getHistoryElementProcessed(deviceType));
+                } else {
+                    historyElements.add(HistoryElementUtil.getHistoryElementRequested(deviceType));
+                }
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findNamePartHistoryForUuid, uuid:                 " + uuid);
+        LOGGER.log(Level.INFO, "findNamePartHistoryForUuid, historyElements.size: " + historyElements.size());
+
+        return historyElements;
+    }
+
+    /**
+     * Find history for name by uuid.
+     * Note uuid (exact match).
+     *
+     * @param uuid uuid to look for
+     * @return a list of entries for history of name part
+     */
+    @GetMapping("/deviceNames/uuid/{uuid}")
+    public List<HistoryElement> findNameHistoryForUuid(@PathVariable("uuid") String uuid) {
+        // check parameters
+        // prepare retrieval of information
+        // retrieve information
+        // prepare return elements
+
+        boolean hasUuid = !StringUtils.isEmpty(uuid);
+
+        final List<HistoryElement> historyElements = Lists.newArrayList();
+        if (!hasUuid) {
+            return historyElements;
+        }
+
+        List<Name> names = holderIRepositories.getNameRepository().findByUuid(uuid);
+        for (Name name : names) {
+            historyElements.add(HistoryElementUtil.getHistoryElement(name));
+        }
+
+        LOGGER.log(Level.INFO, "findNameHistoryForUuid, uuid:                 " + uuid);
+        LOGGER.log(Level.INFO, "findNameHistoryForUuid, historyElements.size: " + historyElements.size());
+
+        return historyElements;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/controller/old/PartControllerV0.java b/src/main/java/org/openepics/names/rest/controller/old/PartControllerV0.java
new file mode 100644
index 0000000..c354d1b
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/controller/old/PartControllerV0.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.controller.old;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.openepics.names.repository.IDeviceGroupRepository;
+import org.openepics.names.repository.IDeviceTypeRepository;
+import org.openepics.names.repository.IDisciplineRepository;
+import org.openepics.names.repository.INameRepository;
+import org.openepics.names.repository.ISubsystemRepository;
+import org.openepics.names.repository.ISystemGroupRepository;
+import org.openepics.names.repository.ISystemRepository;
+import org.openepics.names.repository.model.DeviceGroup;
+import org.openepics.names.repository.model.DeviceType;
+import org.openepics.names.repository.model.Discipline;
+import org.openepics.names.repository.model.Subsystem;
+import org.openepics.names.repository.model.System;
+import org.openepics.names.repository.model.SystemGroup;
+import org.openepics.names.rest.beans.old.PartElement;
+import org.openepics.names.util.HolderIRepositories;
+import org.openepics.names.util.NamingConventionUtil;
+import org.openepics.names.util.old.PartElementUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.google.common.collect.Lists;
+
+/**
+ * This part of REST API provides name part data for Naming application.
+ *
+ * @author Lars Johansson
+ */
+@RestController
+@RequestMapping("/rest/parts")
+@EnableAutoConfiguration
+public class PartControllerV0 {
+
+    // note
+    //     global exception handler available
+
+    /*
+       Methods
+           read      GET /parts/mnemonic/{mnemonic}                - findPartsByMnemonic(String)
+           read      GET /parts/mnemonic/search/{mnemonic}         - findPartsByMnemonicSearch(String)
+           read      GET /parts/mnemonicPath/search/{mnemonicPath} - findPartsByMnemonicPathSearch(String)
+     */
+
+    private static final Logger LOGGER = Logger.getLogger(PartControllerV0.class.getName());
+
+    private HolderIRepositories holderIRepositories;
+
+    @Autowired
+    public PartControllerV0(
+            INameRepository iNameRepository,
+            ISystemGroupRepository iSystemGroupRepository,
+            ISystemRepository iSystemRepository,
+            ISubsystemRepository iSubsystemRepository,
+            IDisciplineRepository iDisciplineRepository,
+            IDeviceGroupRepository iDeviceGroupRepository,
+            IDeviceTypeRepository iDeviceTypeRepository) {
+
+        holderIRepositories = new HolderIRepositories(
+                iNameRepository,
+                iSystemGroupRepository,
+                iSystemRepository,
+                iSubsystemRepository,
+                iDisciplineRepository,
+                iDeviceGroupRepository,
+                iDeviceTypeRepository);
+    }
+
+    /**
+     * Find name parts by mnemonic.
+     * Note mnemonic (exact match, case sensitive).
+     *
+     * @param mnemonic mnemonic to look for
+     * @return a list of name parts
+     */
+    @GetMapping("/mnemonic/{mnemonic}")
+    public List<PartElement> findPartsByMnemonic(@PathVariable("mnemonic") String mnemonic) {
+        // note
+        //     exact match
+        //     case sensitive
+
+        final List<PartElement> partElements = Lists.newArrayList();
+
+        // find in system structure
+
+        List<SystemGroup> systemGroups = holderIRepositories.getSystemGroupRepository().findLatestByMnemonic(mnemonic);
+        List<System>      systems      = holderIRepositories.getSystemRepository().findLatestByMnemonic(mnemonic);
+        List<Subsystem>   subsystems   = holderIRepositories.getSubsystemRepository().findLatestByMnemonic(mnemonic);
+
+        for (SystemGroup systemGroup : systemGroups) {
+            partElements.add(PartElementUtil.getPartElement(systemGroup));
+        }
+        for (System system : systems) {
+            partElements.add(PartElementUtil.getPartElement(system, holderIRepositories));
+        }
+        for (Subsystem subsystem : subsystems) {
+            partElements.add(PartElementUtil.getPartElement(subsystem, holderIRepositories));
+        }
+
+        // find in system structure
+
+        List<Discipline> disciplines = holderIRepositories.getDisciplineRepository().findLatestByMnemonic(mnemonic);
+        List<DeviceType> deviceTypes = holderIRepositories.getDeviceTypeRepository().findLatestByMnemonic(mnemonic);
+
+        for (Discipline discipline : disciplines) {
+            partElements.add(PartElementUtil.getPartElement(discipline));
+        }
+        for (DeviceType deviceType : deviceTypes) {
+            partElements.add(PartElementUtil.getPartElement(deviceType, holderIRepositories));
+        }
+
+        LOGGER.log(Level.INFO, "findPartsByMnemonic, mnemonic:          " + mnemonic);
+        LOGGER.log(Level.INFO, "findPartsByMnemonic, partElements.size: " + partElements.size());
+
+        return partElements;
+    }
+
+    /**
+     * Find name parts by mnemonic search.
+     * Note mnemonic (search, case sensitive, regex).
+     *
+     * @param mnemonic mnemonic to search for
+     * @return a list of name parts
+     */
+    @GetMapping("/mnemonic/search/{mnemonic}")
+    public List<PartElement> findPartsByMnemonicSearch(@PathVariable("mnemonic") String mnemonic) {
+        // note
+        //     search
+        //     case sensitive
+        //     regex
+
+        final List<PartElement> partElements = Lists.newArrayList();
+
+        Pattern pattern = null;
+        try {
+            pattern = Pattern.compile(mnemonic);
+        } catch (PatternSyntaxException e) {
+            LOGGER.log(Level.FINE, e.getMessage(), e);
+        }
+
+        // find in system structure
+
+        List<SystemGroup> systemGroups = holderIRepositories.getSystemGroupRepository().findLatest();
+        List<System>      systems      = holderIRepositories.getSystemRepository().findLatest();
+        List<Subsystem>   subsystems   = holderIRepositories.getSubsystemRepository().findLatest();
+
+        for (SystemGroup systemGroup : systemGroups) {
+            String sub = systemGroup.getMnemonic();
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(systemGroup));
+            }
+        }
+        for (System system : systems) {
+            String sub = system.getMnemonic();
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(system, holderIRepositories));
+            }
+        }
+        for (Subsystem subsystem : subsystems) {
+            String sub = subsystem.getMnemonic();
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(subsystem, holderIRepositories));
+            }
+        }
+
+        // find in device structure
+
+        List<Discipline> disciplines = holderIRepositories.getDisciplineRepository().findLatest();
+        List<DeviceType> deviceTypes = holderIRepositories.getDeviceTypeRepository().findLatest();
+
+        for (Discipline discipline : disciplines) {
+            String sub = discipline.getMnemonic();
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(discipline));
+            }
+        }
+        for (DeviceType deviceType : deviceTypes) {
+            String sub = deviceType.getMnemonic();
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(deviceType, holderIRepositories));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "getAllPartsByMnemonicSearch, mnemonic:          " + mnemonic);
+        LOGGER.log(Level.INFO, "getAllPartsByMnemonicSearch, partElements.size: " + partElements.size());
+
+        return partElements;
+    }
+
+    /**
+     * Find name parts by mnemonic path search.
+     * Note mnemonic path (search, case sensitive, regex).
+     *
+     * @param mnemonicPath mnemonic path to search for
+     * @return a list of name parts
+     */
+    @GetMapping("/mnemonicPath/search/{mnemonicPath}")
+    public List<PartElement> findPartsByMnemonicPathSearch(@PathVariable("mnemonicPath") String mnemonicPath) {
+        // note
+        //     search
+        //     case sensitive
+        //     regex
+
+        final List<PartElement> partElements = Lists.newArrayList();
+
+        Pattern pattern = null;
+        try {
+            pattern = Pattern.compile(mnemonicPath);
+        } catch (PatternSyntaxException e) {
+            LOGGER.log(Level.FINE, e.getMessage(), e);
+        }
+
+        // find in system structure
+
+        List<SystemGroup> systemGroups = holderIRepositories.getSystemGroupRepository().findLatest();
+        List<System>      systems      = holderIRepositories.getSystemRepository().findLatest();
+        List<Subsystem>   subsystems   = holderIRepositories.getSubsystemRepository().findLatest();
+
+        for (SystemGroup systemGroup : systemGroups) {
+            String sub = systemGroup.getMnemonic();
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(systemGroup));
+            }
+        }
+        for (System system : systems) {
+            SystemGroup systemGroup = holderIRepositories.getSystemGroupRepository().findLatestByUuid(system.getParentUuid().toString());
+
+            String sub = NamingConventionUtil.mnemonicPath2String(systemGroup.getName(), system.getName());
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(system, holderIRepositories));
+            }
+        }
+        for (Subsystem subsystem : subsystems) {
+            System      system      = holderIRepositories.getSystemRepository().findLatestByUuid(subsystem.getParentUuid().toString());
+            SystemGroup systemGroup = holderIRepositories.getSystemGroupRepository().findLatestByUuid(system.getParentUuid().toString());
+
+            String sub = NamingConventionUtil.mnemonicPath2String(systemGroup.getMnemonic(), system.getMnemonic(), subsystem.getMnemonic());
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(subsystem, holderIRepositories));
+            }
+        }
+
+        // find in device structure
+
+        List<Discipline> disciplines = holderIRepositories.getDisciplineRepository().findLatest();
+        List<DeviceType> deviceTypes = holderIRepositories.getDeviceTypeRepository().findLatest();
+
+        for (Discipline discipline : disciplines) {
+            String sub = discipline.getMnemonic();
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(discipline));
+            }
+        }
+        for (DeviceType deviceType : deviceTypes) {
+            DeviceGroup deviceGroup = holderIRepositories.getDeviceGroupRepository().findLatestByUuid(deviceType.getParentUuid().toString());
+            Discipline  discipline  = holderIRepositories.getDisciplineRepository().findLatestByUuid(deviceGroup.getParentUuid().toString());
+
+            String sub = NamingConventionUtil.mnemonicPath2String(discipline.getMnemonic(), deviceType.getMnemonic());
+            if (!StringUtils.isEmpty(sub) && pattern.matcher(sub).find()) {
+                partElements.add(PartElementUtil.getPartElement(deviceType, holderIRepositories));
+            }
+        }
+
+        LOGGER.log(Level.INFO, "findPartsByMnemonicPathSearch, mnemonicPath:      " + mnemonicPath);
+        LOGGER.log(Level.INFO, "findPartsByMnemonicPathSearch, partElements.size: " + partElements.size());
+
+        return partElements;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/util/HolderIRepositories.java b/src/main/java/org/openepics/names/util/HolderIRepositories.java
new file mode 100644
index 0000000..d0b8e5f
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/HolderIRepositories.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util;
+
+import org.openepics.names.repository.IDeviceGroupRepository;
+import org.openepics.names.repository.IDeviceTypeRepository;
+import org.openepics.names.repository.IDisciplineRepository;
+import org.openepics.names.repository.INameRepository;
+import org.openepics.names.repository.ISubsystemRepository;
+import org.openepics.names.repository.ISystemGroupRepository;
+import org.openepics.names.repository.ISystemRepository;
+
+/**
+ * Utility class and holder of references to repositories (interfaces).
+ *
+ * @author Lars Johansson
+ */
+public class HolderIRepositories {
+
+    private INameRepository nameRepository;
+
+    private ISystemGroupRepository systemGroupRepository;
+    private ISystemRepository systemRepository;
+    private ISubsystemRepository subsystemRepository;
+
+    private IDisciplineRepository disciplineRepository;
+    private IDeviceGroupRepository deviceGroupRepository;
+    private IDeviceTypeRepository deviceTypeRepository;
+
+    /**
+     * Public constructor to populate references to repositories.
+     *
+     * @param nameRepository reference to name repository
+     * @param systemGroupRepository reference to system group repository
+     * @param systemRepository reference to system repository
+     * @param subsystemRepository reference to subsystem repository
+     * @param disciplineRepository reference to discipline repository
+     * @param deviceGroupRepository reference to device group repository
+     * @param deviceTypeRepository reference to device type repository
+     */
+    public HolderIRepositories(
+            INameRepository nameRepository,
+            ISystemGroupRepository systemGroupRepository,
+            ISystemRepository systemRepository,
+            ISubsystemRepository subsystemRepository,
+            IDisciplineRepository disciplineRepository,
+            IDeviceGroupRepository deviceGroupRepository,
+            IDeviceTypeRepository deviceTypeRepository) {
+        this.nameRepository = nameRepository;
+        this.systemGroupRepository = systemGroupRepository;
+        this.systemRepository = systemRepository;
+        this.subsystemRepository = subsystemRepository;
+        this.disciplineRepository = disciplineRepository;
+        this.deviceGroupRepository = deviceGroupRepository;
+        this.deviceTypeRepository = deviceTypeRepository;
+    }
+
+    /**
+     * Return reference to name repository.
+     *
+     * @return reference to name repository
+     */
+    public INameRepository getNameRepository() {
+        return nameRepository;
+    };
+
+    /**
+     * Return reference to system group repository.
+     *
+     * @return reference to system group repository
+     */
+    public ISystemGroupRepository getSystemGroupRepository() {
+        return systemGroupRepository;
+    };
+    /**
+     * Return reference to system repository.
+     *
+     * @return reference to system repository
+     */
+    public ISystemRepository getSystemRepository() {
+        return systemRepository;
+    };
+    /**
+     * Return reference to subsystem repository.
+     *
+     * @return reference to subsystem repository
+     */
+    public ISubsystemRepository getSubsystemRepository() {
+        return subsystemRepository;
+    };
+
+    /**
+     * Return reference to discipline repository.
+     *
+     * @return reference to discipline repository
+     */
+    public IDisciplineRepository getDisciplineRepository() {
+        return disciplineRepository;
+    };
+    /**
+     * Return reference to device group repository.
+     *
+     * @return reference to device group repository
+     */
+    public IDeviceGroupRepository getDeviceGroupRepository() {
+        return deviceGroupRepository;
+    };
+    /**
+     * Return reference to device type repository.
+     *
+     * @return reference to device type repository
+     */
+    public IDeviceTypeRepository getDeviceTypeRepository() {
+        return deviceTypeRepository;
+    };
+
+}
diff --git a/src/main/java/org/openepics/names/util/HolderSystemDeviceStructure.java b/src/main/java/org/openepics/names/util/HolderSystemDeviceStructure.java
new file mode 100644
index 0000000..456c4c4
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/HolderSystemDeviceStructure.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+
+import org.openepics.names.repository.model.DeviceGroup;
+import org.openepics.names.repository.model.DeviceType;
+import org.openepics.names.repository.model.Discipline;
+import org.openepics.names.repository.model.Subsystem;
+import org.openepics.names.repository.model.System;
+import org.openepics.names.repository.model.SystemGroup;
+
+/**
+ * Utility class and holder of containers for system and device structure content
+ * that are used to populate REST API return elements.
+ * <p>
+ * Class is used for performance reasons to speed up preparation of what is to be returned.
+ * </p>
+ *
+ * @author Lars Johansson
+ */
+public class HolderSystemDeviceStructure {
+
+    private HashMap<UUID, SystemGroup> systemGroups;
+    private HashMap<UUID, System>      systems;
+    private HashMap<UUID, Subsystem>   subsystems;
+
+    private HashMap<UUID, Discipline>  disciplines;
+    private HashMap<UUID, DeviceGroup> deviceGroups;
+    private HashMap<UUID, DeviceType>  deviceTypes;
+
+    private boolean includeDeleted = true;
+
+    /**
+    * Public constructor to prepare containers for system and device structure content.
+    *
+    * @param holderIRepositories
+    */
+   public HolderSystemDeviceStructure (HolderIRepositories holderIRepositories) {
+       this(holderIRepositories, true);
+   }
+
+    /**
+     * Public constructor to prepare containers for system and device structure content.
+     *
+     * @param holderIRepositories holder of references to repositories
+     * @param includeDeleted include deleted structure entries
+     */
+    public HolderSystemDeviceStructure (HolderIRepositories holderIRepositories, boolean includeDeleted) {
+        List<SystemGroup> systemGroups = null;
+        List<System> systems = null;
+        List<Subsystem> subsystems = null;
+        List<Discipline> disciplines = null;
+        List<DeviceGroup> deviceGroups = null;
+        List<DeviceType> deviceTypes = null;
+
+        if (includeDeleted) {
+            systemGroups = holderIRepositories.getSystemGroupRepository().findLatest();
+            systems = holderIRepositories.getSystemRepository().findLatest();
+            subsystems = holderIRepositories.getSubsystemRepository().findLatest();
+            disciplines = holderIRepositories.getDisciplineRepository().findLatest();
+            deviceGroups = holderIRepositories.getDeviceGroupRepository().findLatest();
+            deviceTypes = holderIRepositories.getDeviceTypeRepository().findLatest();
+        } else {
+            systemGroups = holderIRepositories.getSystemGroupRepository().findLatestNotDeleted();
+            systems = holderIRepositories.getSystemRepository().findLatestNotDeleted();
+            subsystems = holderIRepositories.getSubsystemRepository().findLatestNotDeleted();
+            disciplines = holderIRepositories.getDisciplineRepository().findLatestNotDeleted();
+            deviceGroups = holderIRepositories.getDeviceGroupRepository().findLatestNotDeleted();
+            deviceTypes = holderIRepositories.getDeviceTypeRepository().findLatestNotDeleted();
+        }
+
+        // initial capacity
+        //     default load factor 0.75
+        //     set at proper size to avoid rehashing
+        //     size/0.75+1 (may be rounded downwards so possibly +2 instead)
+        this.systemGroups = new HashMap<>((int)(systemGroups.size()/0.75 + 2));
+        this.systems      = new HashMap<>((int)(systems.size()/0.75 + 2));
+        this.subsystems   = new HashMap<>((int)(subsystems.size()/0.75 + 2));
+        this.disciplines  = new HashMap<>((int)(disciplines.size()/0.75 + 2));
+        this.deviceGroups = new HashMap<>((int)(deviceGroups.size()/0.75 + 2));
+        this.deviceTypes  = new HashMap<>((int)(deviceTypes.size()/0.75 + 2));
+
+        for (SystemGroup systemGroup : systemGroups) {
+            this.systemGroups.put(systemGroup.getUuid(), systemGroup);
+        }
+        for (System system : systems) {
+            this.systems.put(system.getUuid(), system);
+        }
+        for (Subsystem subsystem : subsystems) {
+            this.subsystems.put(subsystem.getUuid(), subsystem);
+        }
+        for (Discipline discipline : disciplines) {
+            this.disciplines.put(discipline.getUuid(), discipline);
+        }
+        for (DeviceGroup deviceGroup : deviceGroups) {
+            this.deviceGroups.put(deviceGroup.getUuid(), deviceGroup);
+        }
+        for (DeviceType deviceType : deviceTypes) {
+            this.deviceTypes.put(deviceType.getUuid(), deviceType);
+        }
+    }
+
+    /**
+     * Find system group name part by uuid.
+     *
+     * @param uuid uuid
+     * @return system group name part
+     */
+    public SystemGroup findSystemGroupByUuid(UUID uuid) {
+        return systemGroups.get(uuid);
+    }
+    /**
+     * Find system name part by uuid.
+     *
+     * @param uuid uuid
+     * @return system name part
+     */
+    public System findSystemByUuid(UUID uuid) {
+        return systems.get(uuid);
+    }
+    /**
+     * Find subsystem name part by uuid.
+     *
+     * @param uuid uuid
+     * @return subsystem name part
+     */
+    public Subsystem findSubsystemByUuid(UUID uuid) {
+        return subsystems.get(uuid);
+    }
+
+    /**
+     * Find discipline name part by uuid.
+     *
+     * @param uuid uuid
+     * @return discipline name part
+     */
+    public Discipline findDisciplineByUuid(UUID uuid) {
+        return disciplines.get(uuid);
+    }
+    /**
+     * Find device group name part by uuid.
+     *
+     * @param uuid uuid
+     * @return device group name part
+     */
+    public DeviceGroup findDeviceGroupByUuid(UUID uuid) {
+        return deviceGroups.get(uuid);
+    }
+    /**
+     * Find device type name part by uuid.
+     *
+     * @param uuid uuid
+     * @return device type name part
+     */
+    public DeviceType findDeviceTypeByUuid(UUID uuid) {
+        return deviceTypes.get(uuid);
+    }
+
+    /**
+     * Return if include deleted structure entries.
+     *
+     * @return if include deleted structure entries
+     */
+    public boolean getIncludeDeleted() {
+        return includeDeleted;
+    }
+
+    /**
+     * Return map with key-value pairs (uuid and system group).
+     *
+     * @return map with key-value pairs (uuid and system group)
+     */
+    public HashMap<UUID, SystemGroup> getUuidSystemGroups() {
+        return systemGroups;
+    }
+
+    /**
+     * Return map with key-value pairs (uuid and system).
+     *
+     * @return map with key-value pairs (uuid and system)
+     */
+    public HashMap<UUID, System> getUuidSystems() {
+        return systems;
+    }
+
+    /**
+     * Return map with key-value pairs (uuid and subsystem).
+     *
+     * @return map with key-value pairs (uuid and subsystem)
+     */
+    public HashMap<UUID, Subsystem> getUuidSubsystems() {
+        return subsystems;
+    }
+
+    /**
+     * Return map with key-value pairs (uuid and discipline).
+     *
+     * @return map with key-value pairs (uuid and discipline)
+     */
+    public HashMap<UUID, Discipline> getUuidDisciplines() {
+        return disciplines;
+    }
+
+    /**
+     * Return map with key-value pairs (uuid and device group).
+     *
+     * @return map with key-value pairs (uuid and device group)
+     */
+    public HashMap<UUID, DeviceGroup> getUuidDeviceGroups() {
+        return deviceGroups;
+    }
+
+    /**
+     * Return map with key-value pairs (uuid and device type).
+     *
+     * @return map with key-value pairs (uuid and device type)
+     */
+    public HashMap<UUID, DeviceType> getUuidDeviceTypes() {
+        return deviceTypes;
+    }
+}
diff --git a/src/main/java/org/openepics/names/util/NameUtil.java b/src/main/java/org/openepics/names/util/NameUtil.java
new file mode 100644
index 0000000..d6cff54
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/NameUtil.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util;
+
+import org.openepics.names.repository.model.Name;
+
+/**
+ * Utility class to assist in handling of name content.
+ *
+ * @author Lars Johansson
+ */
+public class NameUtil {
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private NameUtil() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    /**
+     * Return level of system structure for name.
+     * <ul>
+     * <li>1  <--> system group</li>
+     * <li>2  <--> system</li>
+     * <li>3  <--> subsystem</li>
+     * <li>-1 <--> invalid</li>
+     * </ul>
+     *
+     * @param name name content
+     * @return level of system structure
+     */
+    public static int getLevelSystemStructure(Name name) {
+        if (name == null) {
+            return -1;
+        }
+
+        int count = 0;
+        if (name.getSystemgroupUuid() != null) {
+            count++;
+        };
+        if (name.getSystemUuid() != null) {
+            count++;
+        }
+        if (name.getSubsystemUuid() != null) {
+            count++;
+        }
+        if (count != 1) {
+            return -1;
+        }
+
+        return name.getSubsystemUuid() != null
+                ? 3
+                : name.getSystemUuid() != null
+                        ? 2
+                        : name.getSystemgroupUuid() != null
+                                ? 1
+                                : -1;
+    }
+
+    /**
+     * Return level of device structure for name.
+     * <ul>
+     * <li>3  <--> device type</li>
+     * <li>-1 <--> invalid</li>
+     * </ul>
+     *
+     * @param name content
+     * @return level of device structure
+     */
+    public static int getLevelDeviceStructure(Name name) {
+        if (name == null) {
+            return -1;
+        }
+
+        return name.getDevicetypeUuid() != null
+                ? 3
+                : -1;
+    }
+
+//  /**
+//  * Return system structure mnemonic path for name.
+//  *
+//  * @param name name
+//  * @param levelSystemStructure level of system structure
+//  * @param holderIRepositories holder of references to repositories
+//  * @return system structure mnemonic path
+//  */
+// private static String getMnemonicPathSystemStructure(Name name, int levelSystemStructure, HolderIRepositories holderIRepositories) {
+//     // populate return element for system structure
+//     switch (levelSystemStructure) {
+//     case 3: {
+//         Subsystem   subsystem   = holderIRepositories.getSubsystemRepository().findLatestByUuid(name.getSubsystemUuid().toString());
+//         System      system      = holderIRepositories.getSystemRepository().findLatestByUuid(subsystem.getParentUuid().toString());
+//
+//         return system.getMnemonic() + "-" + subsystem.getMnemonic();
+//     }
+//     case 2: {
+//         System      system      = holderIRepositories.getSystemRepository().findLatestByUuid(name.getSystemUuid().toString());
+//
+//         return system.getMnemonic();
+//     }
+//     case 1: {
+//         SystemGroup systemGroup = holderIRepositories.getSystemGroupRepository().findLatestByUuid(name.getSystemgroupUuid().toString());
+//
+//         return systemGroup.getMnemonic();
+//     }
+//     default:
+//         // error
+//         return null;
+//     }
+// }
+//
+// /**
+//  * Return device structure mnemonic path for name.
+//  *
+//  * @param name name
+//  * @param levelDeviceStructure level of device structure
+//  * @param holderIRepositories holder of references to repositories
+//  * @return device structure mnemonic path
+//  */
+// private static String getMnemonicPathDeviceStructure(Name name, int levelDeviceStructure, HolderIRepositories holderIRepositories) {
+//     // populate return element for device structure
+//     switch (levelDeviceStructure) {
+//     case 3: {
+//         DeviceType  deviceType  = holderIRepositories.getDeviceTypeRepository().findLatestByUuid(name.getDevicetypeUuid().toString());
+//         DeviceGroup deviceGroup = holderIRepositories.getDeviceGroupRepository().findLatestByUuid(deviceType.getParentUuid().toString());
+//         Discipline  discipline  = holderIRepositories.getDisciplineRepository().findLatestByUuid(deviceGroup.getParentUuid().toString());
+//
+//         return discipline.getMnemonic() + "-" + deviceType.getMnemonic();
+//     }
+//     default:
+//         // error
+//         return null;
+//     }
+//
+// }
+//
+// /**
+//  * Return system structure mnemonic path for name.
+//  *
+//  * @param name name
+//  * @param levelSystemStructure level of system structure
+//  * @param holderSystemDeviceStructure holder of containers for system and device structure content
+//  * @return system structure mnemonic path
+//  */
+// private static String getMnemonicPathSystemStructure(Name name, int levelSystemStructure, HolderSystemDeviceStructure holderSystemDeviceStructure) {
+//     // populate return element for system structure
+//     switch (levelSystemStructure) {
+//     case 3: {
+//         Subsystem   subsystem   = holderSystemDeviceStructure.findSubsystemByUuid(name.getSubsystemUuid());
+//         System      system      = holderSystemDeviceStructure.findSystemByUuid(subsystem.getParentUuid());
+//
+//         return system.getMnemonic() + "-" + subsystem.getMnemonic();
+//     }
+//     case 2: {
+//         System      system      = holderSystemDeviceStructure.findSystemByUuid(name.getSystemUuid());
+//
+//         return system.getMnemonic();
+//     }
+//     case 1: {
+//         SystemGroup systemGroup = holderSystemDeviceStructure.findSystemGroupByUuid(name.getSystemgroupUuid());
+//
+//         return systemGroup.getMnemonic();
+//     }
+//     default:
+//         // error
+//         return null;
+//     }
+// }
+//
+// /**
+//  * Return device structure mnemonic path for name.
+//  *
+//  * @param name name
+//  * @param levelDeviceStructure level of device structure
+//  * @param holderSystemDeviceStructure holder of containers for system and device structure content
+//  * @return device structure mnemonic path
+//  */
+// private static String getMnemonicPathDeviceStructure(Name name, int levelDeviceStructure, HolderSystemDeviceStructure holderSystemDeviceStructure) {
+//     // populate return element for device structure
+//     switch (levelDeviceStructure) {
+//     case 3: {
+//         DeviceType  deviceType  = holderSystemDeviceStructure.findDeviceTypeByUuid(name.getDevicetypeUuid());
+//         DeviceGroup deviceGroup = holderSystemDeviceStructure.findDeviceGroupByUuid(deviceType.getParentUuid());
+//         Discipline  discipline  = holderSystemDeviceStructure.findDisciplineByUuid(deviceGroup.getParentUuid());
+//
+//         return discipline.getMnemonic() + "-" + deviceType.getMnemonic();
+//     }
+//     default:
+//         // error
+//         return null;
+//     }
+//
+// }
+
+}
diff --git a/src/main/java/org/openepics/names/util/NamingConventionUtil.java b/src/main/java/org/openepics/names/util/NamingConventionUtil.java
new file mode 100644
index 0000000..01d4e1a
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/NamingConventionUtil.java
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2019 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util;
+
+import java.util.Arrays;
+import java.util.StringTokenizer;
+
+import org.apache.commons.lang3.StringUtils;
+import org.openepics.names.repository.model.Discipline;
+
+/**
+ * Utility class to provide split of device name in naming convention into name parts
+ * for system structure and device structure.
+ *
+ * <p>
+ * Note delimiter characters, in and between, system structure and device structure.
+ * <ul>
+ * <li>-
+ * <li>:
+ * </ul>
+ *
+ * @author Lars Johansson
+ *
+ * @see NamingConvention
+ */
+public class NamingConventionUtil {
+
+    // Note
+    //
+    //     ================================================================================
+    //     This class handles system structure and device structure of name convention
+    //     ================================================================================
+    //     ESS Naming Convention
+    //         system structure:device structure:process variable
+    //         ------------------------------------------------------------
+    //         system structure need     to be part of name
+    //         device structure need not to be part of name
+    //         process variable      not to be part of name
+    //         ------------------------------------------------------------
+    //         system structure
+    //             system group
+    //             system
+    //             subsystem
+    //         device structure
+    //             discipline
+    //             device type
+    //             instance index (name)
+    //         ------------------------------------------------------------
+    //         system group is optional
+    //         instance index is optional
+    //     ================================================================================
+    //     Kind of names handled
+    //         CONVENTIONNAME_010
+    //         CONVENTIONNAME_011
+    //         CONVENTIONNAME_010_111
+    //         CONVENTIONNAME_011_110
+    //         CONVENTIONNAME_011_111
+    //         CONVENTIONNAME_111_110
+    //         CONVENTIONNAME_111_111
+    //         ------------------------------------------------------------
+    //         system
+    //         system-subsystem
+    //         system:discipline-deviceType-instanceIndex
+    //         system-subsystem:discipline-deviceType
+    //         system-subsystem:discipline-deviceType-instanceIndex
+    //         systemGroup-system-subsystem:discipline-deviceType
+    //         systemGroup-system-subsystem:discipline-deviceType-instanceIndex
+    //     ================================================================================
+    //     delimiters
+    //         :
+    //         -
+    //     ================================================================================
+    //     This class to be able to handle past and present names
+    //     ================================================================================
+
+    // p&id - pipeline & instrumentation diagram
+    public static final String DISCIPLINE_P_ID       = "P&ID";
+    public static final String DISCIPLINE_SCIENTIFIC = "Scientific";
+
+    private static final String[] DISCIPLINES_P_ID           = {"Cryo", "EMR", "HVAC", "Proc", "SC", "Vac", "WtrC"};
+    private static final String[] MNEMONIC_PATH_P_ID_NUMERIC = {"SC-IOC"};
+
+    private static final String DELIMITER_EXTRA = ":";
+    private static final String DELIMITER_INTRA = "-";
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private NamingConventionUtil() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    /**
+     * Return string array with disciplines for p & id (pipeline & instrumentation diagram).
+     *
+     * @return string array with disciplines for p & id (pipeline & instrumentation diagram)
+     */
+    public static String[] getDisciplinesPID() {
+        return Arrays.copyOf(DISCIPLINES_P_ID, DISCIPLINES_P_ID.length);
+    }
+
+    /**
+     * Return string array with mnemonic paths for p & id (pipeline & instrumentation diagram) numeric.
+     *
+     * @return string array with mnemonic paths for p & id (pipeline & instrumentation diagram) numeric
+     */
+    public static String[] getMnemonicPathsPIDNumeric() {
+        return Arrays.copyOf(MNEMONIC_PATH_P_ID_NUMERIC, MNEMONIC_PATH_P_ID_NUMERIC.length);
+    }
+
+    /**
+     * Extract system group from ESS convention name or <tt>null</tt> if it can not be extracted.
+     *
+     * @param conventionName ESS convention name
+     * @return system group
+     */
+    public static String extractSystemGroup(String conventionName) {
+        if (!StringUtils.isEmpty(conventionName)) {
+            // consider name
+            //     system structure
+            //         before first occurrence of DELIMITER_EXTRA
+
+            StringTokenizer st1 = new StringTokenizer(conventionName, DELIMITER_EXTRA, false);
+            if (st1.countTokens() == 1 || st1.countTokens() == 2 || st1.countTokens() == 3) {
+                StringTokenizer st2 = new StringTokenizer(st1.nextToken(), DELIMITER_INTRA, false);
+                if (st2.countTokens() == 3) {
+                    return st2.nextToken();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract system from ESS convention name or <tt>null</tt> if it can not be extracted.
+     *
+     * @param conventionName ESS convention name
+     * @return system
+     */
+    public static String extractSystem(String conventionName) {
+        if (!StringUtils.isEmpty(conventionName)) {
+            // consider name
+            //     system structure
+            //         before first occurrence of DELIMITER_EXTRA
+
+            StringTokenizer st1 = new StringTokenizer(conventionName, DELIMITER_EXTRA, false);
+            if (st1.countTokens() == 1 || st1.countTokens() == 2 || st1.countTokens() == 3) {
+                StringTokenizer st2 = new StringTokenizer(st1.nextToken(), DELIMITER_INTRA, false);
+                if (st2.countTokens() == 3) {
+                    st2.nextToken();
+                    return st2.nextToken();
+                } else if (st2.countTokens() == 2 || st2.countTokens() == 1) {
+                    return st2.nextToken();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract subsystem from ESS convention name or <tt>null</tt> if it can not be extracted.
+     *
+     * @param conventionName ESS convention name
+     * @return subsystem
+     */
+    public static String extractSubsystem(String conventionName) {
+        if (!StringUtils.isEmpty(conventionName)) {
+            // consider name
+            //     system structure
+            //         before first occurrence of DELIMITER_EXTRA
+
+            StringTokenizer st1 = new StringTokenizer(conventionName, DELIMITER_EXTRA, false);
+            if (st1.countTokens() == 1 || st1.countTokens() == 2 || st1.countTokens() == 3) {
+                StringTokenizer st2 = new StringTokenizer(st1.nextToken(), DELIMITER_INTRA, false);
+                if (st2.countTokens() == 3) {
+                    st2.nextToken();
+                    st2.nextToken();
+                    return st2.nextToken();
+                } else if (st2.countTokens() == 2) {
+                    st2.nextToken();
+                    return st2.nextToken();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract discipline from ESS convention name or <tt>null</tt> if it can not be extracted.
+     *
+     * @param conventionName ESS convention name
+     * @return discipline
+     */
+    public static String extractDiscipline(String conventionName) {
+        if (!StringUtils.isEmpty(conventionName)) {
+            // consider name
+            //     device structure
+            //         after           first  occurrence of DELIMITER_EXTRA
+            //         before possible second occurrence of DELIMITER_EXTRA
+
+            StringTokenizer st1 = new StringTokenizer(conventionName, DELIMITER_EXTRA, false);
+            if (st1.countTokens() == 2 || st1.countTokens() == 3) {
+                st1.nextToken();
+                StringTokenizer st2 = new StringTokenizer(st1.nextToken(), DELIMITER_INTRA, false);
+                if (st2.countTokens() == 3 || st2.countTokens() == 2) {
+                    return st2.nextToken();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract device type from ESS convention name or <tt>null</tt> if it can not be extracted.
+     *
+     * @param conventionName ESS convention name
+     * @return device type
+     */
+    public static String extractDeviceType(String conventionName) {
+        if (!StringUtils.isEmpty(conventionName)) {
+            // consider name
+            //     device structure
+            //         after           first  occurrence of DELIMITER_EXTRA
+            //         before possible second occurrence of DELIMITER_EXTRA
+
+            StringTokenizer st1 = new StringTokenizer(conventionName, DELIMITER_EXTRA, false);
+            if (st1.countTokens() == 2 || st1.countTokens() == 3) {
+                st1.nextToken();
+                StringTokenizer st2 = new StringTokenizer(st1.nextToken(), DELIMITER_INTRA, false);
+                if (st2.countTokens() == 3 || st2.countTokens() == 2) {
+                    st2.nextToken();
+                    return st2.nextToken();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract instance index from ESS convention name or <tt>null</tt> if it can not be extracted.
+     *
+     * @param conventionName ESS convention name
+     * @return instance index
+     */
+    public static String extractInstanceIndex(String conventionName) {
+        if (!StringUtils.isEmpty(conventionName)) {
+            // consider name
+            //     device structure
+            //         after           first  occurrence of DELIMITER_EXTRA
+            //         before possible second occurrence of DELIMITER_EXTRA
+
+            StringTokenizer st1 = new StringTokenizer(conventionName, DELIMITER_EXTRA, false);
+            if (st1.countTokens() == 2 || st1.countTokens() == 3) {
+                st1.nextToken();
+                StringTokenizer st2 = new StringTokenizer(st1.nextToken(), DELIMITER_INTRA, false);
+                if (st2.countTokens() == 3) {
+                    st2.nextToken();
+                    st2.nextToken();
+                    return st2.nextToken();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract mnemonic path for system structure from ESS convention name.
+     *
+     * @param conventionName ESS convention name
+     * @return mnemonic path for system structure
+     */
+    public static String extractMnemonicPathSystemStructure(String conventionName) {
+        if (!StringUtils.isEmpty(conventionName)) {
+            int index = conventionName.indexOf(DELIMITER_EXTRA);
+            if (index != -1) {
+                return conventionName.substring(0, index);
+            } else {
+                return conventionName;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract mnemonic path for device structure from ESS convention name.
+     * Instance index is not part of mnemonic path for device structure.
+     *
+     * @param conventionName ESS convention name
+     * @return mnemonic path for device structure
+     */
+    public static String extractMnemonicPathDeviceStructure(String conventionName) {
+        if (!StringUtils.isEmpty(conventionName)) {
+            int index = conventionName.indexOf(DELIMITER_EXTRA);
+            if (index != -1) {
+                String discipline = extractDiscipline(conventionName);
+                String deviceType = extractDeviceType(conventionName);
+                if (!StringUtils.isEmpty(discipline) && !StringUtils.isEmpty(deviceType)) {
+                    return discipline + DELIMITER_INTRA + deviceType;
+                } else {
+                    return null;
+                }
+            } else {
+                return null;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return instance index style.
+     *
+     * @param conventionName convention name
+     * @return instance index style
+     */
+    public static String getInstanceIndexStyle(String conventionName) {
+        String indexStyle = null;
+        String mnemonicPathDeviceStructure = extractMnemonicPathDeviceStructure(conventionName);
+        if (!StringUtils.isEmpty(mnemonicPathDeviceStructure)) {
+            String discipline = extractDiscipline(conventionName);
+            indexStyle = DISCIPLINE_SCIENTIFIC;
+            for (String str : getDisciplinesPID()) {
+                if (StringUtils.equals(str, discipline)) {
+                    indexStyle = DISCIPLINE_P_ID;
+                    break;
+                }
+            }
+        }
+        return indexStyle;
+    }
+
+    /**
+     * Return instance index style.
+     *
+     * @param discipline discipline
+     * @return instance index style
+     */
+    public static String getInstanceIndexStyle(Discipline discipline) {
+        String indexStyle = null;
+        if (discipline != null && !StringUtils.isEmpty(discipline.getMnemonic())) {
+            indexStyle = DISCIPLINE_SCIENTIFIC;
+            for (String str : getDisciplinesPID()) {
+                if (StringUtils.equals(str, discipline.getMnemonic())) {
+                    indexStyle = DISCIPLINE_P_ID;
+                    break;
+                }
+            }
+        }
+        return indexStyle;
+    }
+
+    /**
+     * Return if discipline is PID discipline.
+     *
+     * @param discipline discipline
+     * @return if discipline is PID
+     */
+    public static boolean isDisciplinePID(String discipline) {
+        if (!StringUtils.isEmpty(discipline)) {
+            for (String s : getDisciplinesPID()) {
+                if (s.equals(discipline)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return if mnemonic path device structure is PID numeric.
+     *
+     * @param mnemonicPath mnemonic path device structure
+     * @return if mnemonic path device structure is PID numeric
+     */
+    public static boolean isMnemonicPathDeviceStructurePIDNumeric(String mnemonicPath) {
+        if (!StringUtils.isEmpty(mnemonicPath)) {
+            for (String s : getMnemonicPathsPIDNumeric()) {
+                if (StringUtils.equals(s, mnemonicPath)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return if convention name is considered OFFSITE.
+     *
+     * @param conventionName ESS convention name
+     * @return               if convention name is considered OFFSITE
+     */
+    public static boolean isOffsite(String conventionName) {
+        return !StringUtils.isEmpty(extractSystemGroup(conventionName))
+                && !StringUtils.isEmpty(extractSystem(conventionName))
+                && !StringUtils.isEmpty(extractSubsystem(conventionName));
+    }
+
+    /**
+     * Utility method to convert a mnemonic path (an array of strings) to a string
+     * with {@link NamingConventionUtil#DELIMITER_INTRA} as path separator.
+     *
+     * @param mnemonicPath array of strings
+     * @return mnemonic path
+     */
+    public static String mnemonicPath2String(String... mnemonicPath) {
+        if (mnemonicPath != null) {
+            String value = StringUtils.join(mnemonicPath, DELIMITER_INTRA);
+            value = StringUtils.replace(value, DELIMITER_INTRA + DELIMITER_INTRA, DELIMITER_INTRA);
+            return StringUtils.strip(value, DELIMITER_INTRA);
+        }
+        return null;
+    }
+
+    /**
+     * Utility method to convert a string to a mnemonic path (an array of strings)
+     * with {@link NamingConventionUtil#DELIMITER_INTRA} as path separator.
+     *
+     * @param name name
+     * @return mnemonic path (an array of strings)
+     */
+    public static String[] string2MnemonicPath(String name) {
+        if (name != null) {
+            return StringUtils.split(name, DELIMITER_INTRA);
+        }
+        return null;
+    }
+
+    /**
+     * Utility method to return mnemonic path system structure for name.
+     *
+     * @param mnemonicPathSystemStructure mnemonic path system structure
+     * @return mnemonic path system structure for name
+     */
+    public static String mnemonicPathSystemStructure4Name(String mnemonicPathSystemStructure) {
+        // mnemonicPathSystemStructure A-B-C ---> B-C
+        // mnemonicPathSystemStructure A-B   ---> A-B
+        // mnemonicPathSystemStructure A     ---> A
+
+        String[] mnemonicPath = NamingConventionUtil.string2MnemonicPath(mnemonicPathSystemStructure);
+        if (mnemonicPath != null && mnemonicPath.length == 3) {
+            return mnemonicPath[1] + "-" + mnemonicPath[2];
+        }
+        return mnemonicPathSystemStructure;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/util/old/DeviceNameElementUtil.java b/src/main/java/org/openepics/names/util/old/DeviceNameElementUtil.java
new file mode 100644
index 0000000..ce1b521
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/old/DeviceNameElementUtil.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util.old;
+
+import org.openepics.names.repository.model.DeviceGroup;
+import org.openepics.names.repository.model.DeviceType;
+import org.openepics.names.repository.model.Discipline;
+import org.openepics.names.repository.model.Name;
+import org.openepics.names.repository.model.Subsystem;
+import org.openepics.names.repository.model.System;
+import org.openepics.names.repository.model.SystemGroup;
+import org.openepics.names.rest.beans.old.DeviceNameElement;
+import org.openepics.names.util.HolderIRepositories;
+import org.openepics.names.util.HolderSystemDeviceStructure;
+import org.openepics.names.util.NameUtil;
+
+/**
+ * Utility class to assist in populating device name elements based on repository content.
+ *
+ * @author Lars Johansson
+ */
+public class DeviceNameElementUtil {
+
+    protected static final String ACTIVE   = "ACTIVE";
+    protected static final String DELETED  = "DELETED";
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private DeviceNameElementUtil() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    /**
+     * Populate and return device name element for name.
+     *
+     * @param name name
+     * @param holderSystemDeviceStructure holder of containers for system and device structure content
+     * @return device name element
+     */
+    public static DeviceNameElement getDeviceNameElement(Name name, HolderSystemDeviceStructure holderSystemDeviceStructure) {
+        if (name == null) {
+            return null;
+        }
+
+        // using holder of containers for system and device structure content
+        //     for performance reasons to speed up preparation of what is to be returned
+
+        // find out how to populate return element for system structure, device structure
+        int levelSystemStructure = NameUtil.getLevelSystemStructure(name);
+        int levelDeviceStructure = NameUtil.getLevelDeviceStructure(name);
+
+        // levelSystemStructure -1 ---> error
+        // levelDeviceStructure -1 ---> error
+
+        final DeviceNameElement deviceNameElement = new DeviceNameElement();
+
+        // populate return element for system structure
+        switch (levelSystemStructure) {
+        case 3: {
+            Subsystem   subsystem   = holderSystemDeviceStructure.findSubsystemByUuid(name.getSubsystemUuid());
+            System      system      = holderSystemDeviceStructure.findSystemByUuid(subsystem.getParentUuid());
+            SystemGroup systemGroup = holderSystemDeviceStructure.findSystemGroupByUuid(system.getParentUuid());
+
+            deviceNameElement.setSubsystem(subsystem.getMnemonic());
+            deviceNameElement.setSystem(system.getMnemonic());
+            deviceNameElement.setSystemGroup(systemGroup.getMnemonic());
+            break;
+        }
+        case 2: {
+            System      system      = holderSystemDeviceStructure.findSystemByUuid(name.getSystemUuid());
+            SystemGroup systemGroup = holderSystemDeviceStructure.findSystemGroupByUuid(system.getParentUuid());
+
+            deviceNameElement.setSystem(system.getMnemonic());
+            deviceNameElement.setSystemGroup(systemGroup.getMnemonic());
+            break;
+        }
+        case 1: {
+            SystemGroup systemGroup = holderSystemDeviceStructure.findSystemGroupByUuid(name.getSystemgroupUuid());
+
+            deviceNameElement.setSystemGroup(systemGroup.getMnemonic());
+            break;
+        }
+        default:
+            // error
+            break;
+        }
+
+        // populate return element for device structure
+        switch (levelDeviceStructure) {
+        case 3: {
+            DeviceType  deviceType  = holderSystemDeviceStructure.findDeviceTypeByUuid(name.getDevicetypeUuid());
+            DeviceGroup deviceGroup = holderSystemDeviceStructure.findDeviceGroupByUuid(deviceType.getParentUuid());
+            Discipline  discipline  = holderSystemDeviceStructure.findDisciplineByUuid(deviceGroup.getParentUuid());
+
+            deviceNameElement.setDeviceType(deviceType.getMnemonic());
+            deviceNameElement.setDiscipline(discipline.getMnemonic());
+            break;
+        }
+        default:
+            // error
+            break;
+        }
+
+        deviceNameElement.setUuid(name.getUuid());
+        deviceNameElement.setInstanceIndex(name.getInstanceIndex());
+        deviceNameElement.setName(name.getConventionName());
+        deviceNameElement.setDescription(name.getDescription());
+        deviceNameElement.setStatus(name.isDeleted() ? DELETED : ACTIVE);
+
+        return deviceNameElement;
+    }
+
+    /**
+     * Populate and return device name element for name.
+     *
+     * @param name name
+     * @param holderIRepositories holder of references to repositories
+     * @return device name element
+     */
+    public static DeviceNameElement getDeviceNameElement(Name name, HolderIRepositories holderIRepositories) {
+        if (name == null) {
+            return null;
+        }
+
+        // find out how to populate return element for system structure, device structure
+        int levelSystemStructure = NameUtil.getLevelSystemStructure(name);
+        int levelDeviceStructure = NameUtil.getLevelDeviceStructure(name);
+
+        // levelSystemStructure -1 ---> error
+        // levelDeviceStructure -1 ---> error
+
+        final DeviceNameElement deviceNameElement = new DeviceNameElement();
+
+        // populate return element for system structure
+        switch (levelSystemStructure) {
+        case 3: {
+            Subsystem   subsystem   = holderIRepositories.getSubsystemRepository().findLatestByUuid(name.getSubsystemUuid().toString());
+            System      system      = holderIRepositories.getSystemRepository().findLatestByUuid(subsystem.getParentUuid().toString());
+            SystemGroup systemGroup = holderIRepositories.getSystemGroupRepository().findLatestByUuid(system.getParentUuid().toString());
+
+            deviceNameElement.setSubsystem(subsystem.getMnemonic());
+            deviceNameElement.setSystem(system.getMnemonic());
+            deviceNameElement.setSystemGroup(systemGroup.getMnemonic());
+            break;
+        }
+        case 2: {
+            System      system      = holderIRepositories.getSystemRepository().findLatestByUuid(name.getSystemUuid().toString());
+            SystemGroup systemGroup = holderIRepositories.getSystemGroupRepository().findLatestByUuid(system.getParentUuid().toString());
+
+            deviceNameElement.setSystem(system.getMnemonic());
+            deviceNameElement.setSystemGroup(systemGroup.getMnemonic());
+            break;
+        }
+        case 1: {
+            SystemGroup systemGroup = holderIRepositories.getSystemGroupRepository().findLatestByUuid(name.getSystemgroupUuid().toString());
+
+            deviceNameElement.setSystemGroup(systemGroup.getMnemonic());
+            break;
+        }
+        default:
+            // error
+            break;
+        }
+
+        // populate return element for device structure
+        switch (levelDeviceStructure) {
+        case 3: {
+            DeviceType  deviceType  = holderIRepositories.getDeviceTypeRepository().findLatestByUuid(name.getDevicetypeUuid().toString());
+            DeviceGroup deviceGroup = holderIRepositories.getDeviceGroupRepository().findLatestByUuid(deviceType.getParentUuid().toString());
+            Discipline  discipline  = holderIRepositories.getDisciplineRepository().findLatestByUuid(deviceGroup.getParentUuid().toString());
+
+            deviceNameElement.setDeviceType(deviceType.getMnemonic());
+            deviceNameElement.setDiscipline(discipline.getMnemonic());
+            break;
+        }
+        default:
+            // error
+            break;
+        }
+
+        deviceNameElement.setUuid(name.getUuid());
+        deviceNameElement.setInstanceIndex(name.getInstanceIndex());
+        deviceNameElement.setName(name.getConventionName());
+        deviceNameElement.setDescription(name.getDescription());
+        deviceNameElement.setStatus(name.isDeleted() ? DELETED : ACTIVE);
+
+        return deviceNameElement;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/util/old/HistoryElementUtil.java b/src/main/java/org/openepics/names/util/old/HistoryElementUtil.java
new file mode 100644
index 0000000..b5a1fe6
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/old/HistoryElementUtil.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util.old;
+
+import java.text.SimpleDateFormat;
+import java.util.UUID;
+
+import org.openepics.names.old.business.NameRevisionStatus;
+import org.openepics.names.repository.model.DeviceGroup;
+import org.openepics.names.repository.model.DeviceType;
+import org.openepics.names.repository.model.Discipline;
+import org.openepics.names.repository.model.Name;
+import org.openepics.names.repository.model.Subsystem;
+import org.openepics.names.repository.model.System;
+import org.openepics.names.repository.model.SystemGroup;
+import org.openepics.names.rest.beans.old.HistoryElement;
+
+/**
+ * Utility class to assist in populating history elements based on repository content.
+ *
+ * @author Lars Johansson
+ */
+public class HistoryElementUtil {
+
+    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private HistoryElementUtil() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    /**
+     * Populate and return history element for system group with focus on processed.
+     *
+     * @param systemGroup system group
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementProcessed(SystemGroup systemGroup) {
+        if (systemGroup == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                systemGroup.getUuid(),
+                systemGroup.getName(),
+                systemGroup.getMnemonic(),
+                systemGroup.getDescription(),
+                systemGroup.getStatus() != null ? systemGroup.getStatus().toString() : "",
+                systemGroup.getProcessed() != null ? SDF.format(systemGroup.getProcessed()) : "",
+                systemGroup.getProcessedBy(),
+                systemGroup.getProcessedComment());
+    }
+    /**
+     * Populate and return history element for system group with focus on requested.
+     *
+     * @param systemGroup system group
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementRequested(SystemGroup systemGroup) {
+        if (systemGroup == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                systemGroup.getUuid(),
+                systemGroup.getName(),
+                systemGroup.getMnemonic(),
+                systemGroup.getDescription(),
+                NameRevisionStatus.PENDING.name(),
+                systemGroup.getRequested() != null ? SDF.format(systemGroup.getRequested()) : "",
+                systemGroup.getRequestedBy(),
+                systemGroup.getRequestedComment());
+    }
+    /**
+     * Populate and return history element for system with focus on processed.
+     *
+     * @param system system
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementProcessed(System system) {
+        if (system == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                system.getUuid(),
+                system.getName(),
+                system.getMnemonic(),
+                system.getDescription(),
+                system.getStatus() != null ? system.getStatus().toString() : "",
+                system.getProcessed() != null ? SDF.format(system.getProcessed()) : "",
+                system.getProcessedBy(),
+                system.getProcessedComment());
+    }
+    /**
+     * Populate and return history element for system with focus on requested.
+     *
+     * @param system system
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementRequested(System system) {
+        if (system == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                system.getUuid(),
+                system.getName(),
+                system.getMnemonic(),
+                system.getDescription(),
+                NameRevisionStatus.PENDING.name(),
+                system.getRequested() != null ? SDF.format(system.getRequested()) : "",
+                system.getRequestedBy(),
+                system.getRequestedComment());
+    }
+    /**
+     * Populate and return history element for subsystem with focus on processed.
+     *
+     * @param subsystem subsystem
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementProcessed(Subsystem subsystem) {
+        if (subsystem == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                subsystem.getUuid(),
+                subsystem.getName(),
+                subsystem.getMnemonic(),
+                subsystem.getDescription(),
+                subsystem.getStatus() != null ? subsystem.getStatus().toString() : "",
+                subsystem.getProcessed() != null ? SDF.format(subsystem.getProcessed()) : "",
+                subsystem.getProcessedBy(),
+                subsystem.getProcessedComment());
+    }
+    /**
+     * Populate and return history element for subsystem with focus on requested.
+     *
+     * @param subsystem subsystem
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementRequested(Subsystem subsystem) {
+        if (subsystem == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                subsystem.getUuid(),
+                subsystem.getName(),
+                subsystem.getMnemonic(),
+                subsystem.getDescription(),
+                NameRevisionStatus.PENDING.name(),
+                subsystem.getRequested() != null ? SDF.format(subsystem.getRequested()) : "",
+                subsystem.getRequestedBy(),
+                subsystem.getRequestedComment());
+    }
+
+    /**
+     * Populate and return history element for discipline with focus on processed.
+     *
+     * @param discipline discipline
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementProcessed(Discipline discipline) {
+        if (discipline == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                discipline.getUuid(),
+                discipline.getName(),
+                discipline.getMnemonic(),
+                discipline.getDescription(),
+                discipline.getStatus() != null ? discipline.getStatus().toString() : "",
+                discipline.getProcessed() != null ? SDF.format(discipline.getProcessed()) : "",
+                discipline.getProcessedBy(),
+                discipline.getProcessedComment());
+    }
+    /**
+     * Populate and return history element for discipline with focus on requested.
+     *
+     * @param discipline discipline
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementRequested(Discipline discipline) {
+        if (discipline == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                discipline.getUuid(),
+                discipline.getName(),
+                discipline.getMnemonic(),
+                discipline.getDescription(),
+                NameRevisionStatus.PENDING.name(),
+                discipline.getRequested() != null ? SDF.format(discipline.getRequested()) : "",
+                discipline.getRequestedBy(),
+                discipline.getRequestedComment());
+    }
+    /**
+     * Populate and return history element for device group with focus on processed.
+     *
+     * @param deviceGroup device group
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementProcessed(DeviceGroup deviceGroup) {
+        if (deviceGroup == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                deviceGroup.getUuid(),
+                deviceGroup.getName(),
+                deviceGroup.getMnemonic(),
+                deviceGroup.getDescription(),
+                deviceGroup.getStatus() != null ? deviceGroup.getStatus().toString() : "",
+                deviceGroup.getProcessed() != null ? SDF.format(deviceGroup.getProcessed()) : "",
+                deviceGroup.getProcessedBy(),
+                deviceGroup.getProcessedComment());
+    }
+    /**
+     * Populate and return history element for device group with focus on requested.
+     *
+     * @param deviceGroup device group
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementRequested(DeviceGroup deviceGroup) {
+        if (deviceGroup == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                deviceGroup.getUuid(),
+                deviceGroup.getName(),
+                deviceGroup.getMnemonic(),
+                deviceGroup.getDescription(),
+                NameRevisionStatus.PENDING.name(),
+                deviceGroup.getRequested() != null ? SDF.format(deviceGroup.getRequested()) : "",
+                deviceGroup.getRequestedBy(),
+                deviceGroup.getRequestedComment());
+    }
+    /**
+     * Populate and return history element for device type with focus on processed.
+     *
+     * @param deviceType device type
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementProcessed(DeviceType deviceType) {
+        if (deviceType == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                deviceType.getUuid(),
+                deviceType.getName(),
+                deviceType.getMnemonic(),
+                deviceType.getDescription(),
+                deviceType.getStatus() != null ? deviceType.getStatus().toString() : "",
+                deviceType.getProcessed() != null ? SDF.format(deviceType.getProcessed()) : "",
+                deviceType.getProcessedBy(),
+                deviceType.getProcessedComment());
+    }
+    /**
+     * Populate and return history element for device type with focus on requested.
+     *
+     * @param deviceType device type
+     * @return history element
+     */
+    public static HistoryElement getHistoryElementRequested(DeviceType deviceType) {
+        if (deviceType == null) {
+            return null;
+        }
+
+        return getHistoryElement(
+                deviceType.getUuid(),
+                deviceType.getName(),
+                deviceType.getMnemonic(),
+                deviceType.getDescription(),
+                NameRevisionStatus.PENDING.name(),
+                deviceType.getRequested() != null ? SDF.format(deviceType.getRequested()) : "",
+                deviceType.getRequestedBy(),
+                deviceType.getRequestedComment());
+    }
+
+    /**
+     * Populate and return history element.
+     *
+     * @param uuid uuid
+     * @param fullName full name
+     * @param mnemonic mnemonic
+     * @param description description
+     * @param status status
+     * @param date date
+     * @param user user
+     * @param message message
+     * @return history element
+     */
+    private static HistoryElement getHistoryElement(UUID uuid, String fullName, String mnemonic, String description, String status, String date, String user, String message) {
+        return new HistoryElement(uuid, fullName, mnemonic, description, status, date, user, message);
+    }
+
+    /**
+     * Populate and return structure element for name.
+     *
+     * @param name name
+     * @return history element
+     */
+    public static HistoryElement getHistoryElement(Name name) {
+        if (name == null) {
+            return null;
+        }
+
+        return new HistoryElement(
+                name.getUuid(),
+                name.getConventionName(),
+                name.getInstanceIndex(),
+                name.getDescription(),
+                name.getStatus() != null ? name.getStatus().toString() : "",
+                name.getRequested() != null ? SDF.format(name.getRequested()) : "",
+                name.getRequestedBy(),
+                name.getRequestedComment());
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/util/old/PartElementUtil.java b/src/main/java/org/openepics/names/util/old/PartElementUtil.java
new file mode 100644
index 0000000..a62ad5b
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/old/PartElementUtil.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util.old;
+
+import org.openepics.names.repository.model.DeviceGroup;
+import org.openepics.names.repository.model.DeviceType;
+import org.openepics.names.repository.model.Discipline;
+import org.openepics.names.repository.model.Subsystem;
+import org.openepics.names.repository.model.System;
+import org.openepics.names.repository.model.SystemGroup;
+import org.openepics.names.rest.beans.old.PartElement;
+import org.openepics.names.util.HolderIRepositories;
+import org.openepics.names.util.NamingConventionUtil;
+
+/**
+ * Utility class to assist in populating part elements based on repository content.
+ *
+ * @author Lars Johansson
+ */
+public class PartElementUtil {
+
+    protected static final String SYSTEM_STRUCTURE = "System Structure";
+    protected static final String DEVICE_STRUCTURE = "Device Structure";
+    protected static final String DEVICE_REGISTRY  = "Device Registry";
+
+    protected static final String ONE   = "1";
+    protected static final String TWO   = "2";
+    protected static final String THREE = "3";
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private PartElementUtil() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    /**
+     * Populate and return part element for system group.
+     *
+     * @param systemGroup system group
+     * @return part element
+     */
+    public static PartElement getPartElement(SystemGroup systemGroup) {
+        if (systemGroup == null) {
+            return null;
+        }
+
+        return new PartElement(
+                SYSTEM_STRUCTURE,
+                systemGroup.getUuid(),
+                systemGroup.getName(),
+                systemGroup.getName(),
+                systemGroup.getMnemonic(),
+                systemGroup.getMnemonic(),
+                ONE,
+                systemGroup.getDescription(),
+                systemGroup.getStatus().toString());
+    }
+
+    /**
+     * Populate and return part element for system.
+     *
+     * @param system system
+     * @return part element
+     */
+    public static PartElement getPartElement(System system, HolderIRepositories holderIRepositories) {
+        if (system == null) {
+            return null;
+        }
+
+        SystemGroup systemGroup = holderIRepositories.getSystemGroupRepository().findLatestByUuid(system.getParentUuid().toString());
+
+        return new PartElement(
+                SYSTEM_STRUCTURE,
+                system.getUuid(),
+                system.getName(),
+                NamingConventionUtil.mnemonicPath2String(systemGroup.getName(), system.getName()),
+                system.getMnemonic(),
+                NamingConventionUtil.mnemonicPath2String(systemGroup.getMnemonic(), system.getMnemonic()),
+                TWO,
+                system.getDescription(),
+                system.getStatus().toString());
+    }
+
+    /**
+     * Populate and return part element for subsystem.
+     *
+     * @param subsystem subsystem
+     * @return part element
+     */
+    public static PartElement getPartElement(Subsystem subsystem, HolderIRepositories holderIRepositories) {
+        if (subsystem == null) {
+            return null;
+        }
+
+        System      system      = holderIRepositories.getSystemRepository().findLatestByUuid(subsystem.getParentUuid().toString());
+        SystemGroup systemGroup = holderIRepositories.getSystemGroupRepository().findLatestByUuid(system.getParentUuid().toString());
+
+        return new PartElement(
+                SYSTEM_STRUCTURE,
+                subsystem.getUuid(),
+                subsystem.getName(),
+                NamingConventionUtil.mnemonicPath2String(systemGroup.getName(), system.getName(), subsystem.getName()),
+                subsystem.getMnemonic(),
+                NamingConventionUtil.mnemonicPath2String(systemGroup.getMnemonic(), system.getMnemonic(), subsystem.getMnemonic()),
+                THREE,
+                subsystem.getDescription(),
+                subsystem.getStatus().toString());
+    }
+
+    /**
+     * Populate and return part element for discipline.
+     *
+     * @param discipline discipline
+     * @return part element
+     */
+    public static PartElement getPartElement(Discipline discipline) {
+        if (discipline == null) {
+            return null;
+        }
+
+        return new PartElement(
+                DEVICE_STRUCTURE,
+                discipline.getUuid(),
+                discipline.getName(),
+                discipline.getName(),
+                discipline.getMnemonic(),
+                discipline.getMnemonic(),
+                ONE,
+                discipline.getDescription(),
+                discipline.getStatus().toString());
+    }
+
+    /**
+     * Populate and return part element for device type.
+     *
+     * @param deviceType device type
+     * @return part element
+     */
+    public static PartElement getPartElement(DeviceType deviceType, HolderIRepositories holderIRepositories) {
+        if (deviceType == null) {
+            return null;
+        }
+
+        DeviceGroup deviceGroup = holderIRepositories.getDeviceGroupRepository().findLatestByUuid(deviceType.getParentUuid().toString());
+        Discipline  discipline  = holderIRepositories.getDisciplineRepository().findLatestByUuid(deviceGroup.getParentUuid().toString());
+
+        return new PartElement(
+                DEVICE_STRUCTURE,
+                deviceType.getUuid(),
+                deviceType.getName(),
+                NamingConventionUtil.mnemonicPath2String(discipline.getName(), deviceType.getName()),
+                NamingConventionUtil.mnemonicPath2String(discipline.getMnemonic(), deviceType.getMnemonic()),
+                deviceType.getMnemonic(),
+                THREE,
+                deviceType.getDescription(),
+                deviceType.getStatus().toString());
+    }
+
+}
diff --git a/src/test/java/org/openepics/names/NamingApplicationTests.java b/src/test/java/org/openepics/names/NamingApplicationTests.java
new file mode 100644
index 0000000..41db805
--- /dev/null
+++ b/src/test/java/org/openepics/names/NamingApplicationTests.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class NamingApplicationTests {
+
+	@Test
+	void contextLoads() {
+	}
+
+}
diff --git a/src/test/java/org/openepics/names/util/NameUtilTest.java b/src/test/java/org/openepics/names/util/NameUtilTest.java
new file mode 100644
index 0000000..99c666f
--- /dev/null
+++ b/src/test/java/org/openepics/names/util/NameUtilTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.Test;
+import org.openepics.names.repository.model.Name;
+
+/**
+ * Unit tests for NamingUtil class.
+ *
+ * @author Lars Johansson
+ *
+ * @see NameUtil
+ */
+public class NameUtilTest {
+
+    /**
+     * Test of get level of system structure for name.
+     */
+    @Test
+    public void getLevelSystemStructure() {
+        Name name = new Name();
+        assertEquals(-1, NameUtil.getLevelSystemStructure(name));
+
+        name.setSubsystemUuid(UUID.randomUUID());
+        name.setSystemUuid(null);
+        name.setSystemgroupUuid(null);
+        assertEquals(3, NameUtil.getLevelSystemStructure(name));
+
+        name.setSubsystemUuid(null);
+        name.setSystemUuid(UUID.randomUUID());
+        name.setSystemgroupUuid(null);
+        assertEquals(2, NameUtil.getLevelSystemStructure(name));
+
+        name.setSubsystemUuid(UUID.randomUUID());
+        name.setSystemUuid(UUID.randomUUID());
+        name.setSystemgroupUuid(null);
+        assertEquals(-1, NameUtil.getLevelSystemStructure(name));
+
+        name.setSubsystemUuid(null);
+        name.setSystemUuid(null);
+        name.setSystemgroupUuid(UUID.randomUUID());
+        assertEquals(1, NameUtil.getLevelSystemStructure(name));
+
+        name.setSubsystemUuid(UUID.randomUUID());
+        name.setSystemUuid(null);
+        name.setSystemgroupUuid(UUID.randomUUID());
+        assertEquals(-1, NameUtil.getLevelSystemStructure(name));
+
+        name.setSubsystemUuid(null);
+        name.setSystemUuid(UUID.randomUUID());
+        name.setSystemgroupUuid(UUID.randomUUID());
+        assertEquals(-1, NameUtil.getLevelSystemStructure(name));
+
+        name.setSubsystemUuid(UUID.randomUUID());
+        name.setSystemUuid(UUID.randomUUID());
+        name.setSystemgroupUuid(UUID.randomUUID());
+        assertEquals(-1, NameUtil.getLevelSystemStructure(name));
+    }
+
+    /**
+     * Test of get level of device structure for name.
+     */
+    @Test
+    public void getLevelDeviceStructure() {
+        Name name = new Name();
+        assertEquals(-1, NameUtil.getLevelDeviceStructure(name));
+
+        name.setDevicetypeUuid(UUID.randomUUID());
+        assertEquals(3, NameUtil.getLevelDeviceStructure(name));
+    }
+
+}
diff --git a/src/test/java/org/openepics/names/util/NamingConventionUtilTest.java b/src/test/java/org/openepics/names/util/NamingConventionUtilTest.java
new file mode 100644
index 0000000..01b7acb
--- /dev/null
+++ b/src/test/java/org/openepics/names/util/NamingConventionUtilTest.java
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2019 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+import org.openepics.names.repository.model.Discipline;
+
+/**
+ * Unit tests for NamingConventionUtil class.
+ *
+ * @author Lars Johansson
+ *
+ * @see NamingConventionUtil
+ */
+public class NamingConventionUtilTest {
+
+    // conventionname_abc_def
+    //     a - 1/0 - system group   or not
+    //     b - 1/0 - system         or not
+    //     c - 1/0 - subsystem      or not
+    //     d - 1/0 - discipline     or not
+    //     e - 1/0 - device type    or not
+    //     f - 1/0 - instance index or not
+
+    private static final String NULL  = null;
+    private static final String EMPTY = "";
+    private static final String DUMMY = "DUMMY";
+
+    private static final String ACC           = "Acc";
+    private static final String LEBT          = "LEBT";
+    private static final String ZERO_ONE_ZERO = "010";
+
+    private static final String CONVENTIONNAME_010             = "LEBT";
+    private static final String CONVENTIONNAME_011             = "LEBT-010";
+    private static final String CONVENTIONNAME_111             = "Acc-LEBT-010";
+
+    private static final String CONVENTIONNAME_010_111         = "CWL:WtrC-EC-003";
+    private static final String CONVENTIONNAME_011_110         = "LEBT-010:PwrC-PSChop";
+    private static final String CONVENTIONNAME_011_111         = "CWL-CWSE05:WtrC-EC-003";
+    private static final String CONVENTIONNAME_111_110         = "Acc-LEBT-010:PwrC-PSChop";
+    private static final String CONVENTIONNAME_111_111         = "DUMMY-CWL-CWSE05:WtrC-EC-003";
+
+    private static final String CONVENTIONNAME_011_111_SC1     = "CWL-CWSE05:SC-EC-003";
+    private static final String CONVENTIONNAME_011_111_SC2     = "CWL-CWSE05:SC-IOC-003";
+
+    private static final String CONVENTIONNAME_011_111_EQCLASS = "CW1-CWSE5:WTRC-EC-3";
+    private static final String CONVENTIONNAME_111_111_EQCLASS = "DUMMY-CW1-CWSE5:WTRC-EC-3";
+
+    /**
+     * Test of extraction of system group from convention name.
+     */
+    @Test
+    public void extractSystemGroup() {
+        assertNull(NamingConventionUtil.extractSystemGroup(NULL));
+        assertNull(NamingConventionUtil.extractSystemGroup(EMPTY));
+        assertNull(NamingConventionUtil.extractSystemGroup(DUMMY));
+
+        assertEquals(NULL,      NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_010));
+        assertEquals(NULL,      NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_011));
+
+        assertEquals(NULL,      NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_010_111));
+        assertEquals(NULL,      NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_011_110));
+        assertEquals(NULL,      NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_011_111));
+        assertEquals(ACC,       NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_111_110));
+        assertEquals(DUMMY,     NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_111_111));
+
+        assertEquals(NULL,      NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_011_111_SC1));
+        assertEquals(NULL,      NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals(NULL,      NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals(DUMMY,     NamingConventionUtil.extractSystemGroup(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test of extraction of system from convention name.
+     */
+    @Test
+    public void extractSystem() {
+        assertNull(NamingConventionUtil.extractSystem(NULL));
+        assertNull(NamingConventionUtil.extractSystem(EMPTY));
+        assertEquals(DUMMY,     NamingConventionUtil.extractSystem(DUMMY));
+
+        assertEquals("LEBT",    NamingConventionUtil.extractSystem(CONVENTIONNAME_010));
+        assertEquals("LEBT",    NamingConventionUtil.extractSystem(CONVENTIONNAME_011));
+
+        assertEquals("CWL",     NamingConventionUtil.extractSystem(CONVENTIONNAME_010_111));
+        assertEquals("LEBT",    NamingConventionUtil.extractSystem(CONVENTIONNAME_011_110));
+        assertEquals("CWL",     NamingConventionUtil.extractSystem(CONVENTIONNAME_011_111));
+        assertEquals("LEBT",    NamingConventionUtil.extractSystem(CONVENTIONNAME_111_110));
+        assertEquals("CWL",     NamingConventionUtil.extractSystem(CONVENTIONNAME_111_111));
+
+        assertEquals("CWL",     NamingConventionUtil.extractSystem(CONVENTIONNAME_011_111_SC1));
+        assertEquals("CWL",     NamingConventionUtil.extractSystem(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals("CW1",     NamingConventionUtil.extractSystem(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals("CW1",     NamingConventionUtil.extractSystem(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test of extraction of subsystem group from convention name.
+     */
+    @Test
+    public void extractSubsystem() {
+        assertNull(NamingConventionUtil.extractSubsystem(NULL));
+        assertNull(NamingConventionUtil.extractSubsystem(EMPTY));
+        assertNull(NamingConventionUtil.extractSubsystem(DUMMY));
+
+        assertEquals(NULL,      NamingConventionUtil.extractSubsystem(CONVENTIONNAME_010));
+        assertEquals("010",     NamingConventionUtil.extractSubsystem(CONVENTIONNAME_011));
+
+        assertEquals(NULL,      NamingConventionUtil.extractSubsystem(CONVENTIONNAME_010_111));
+        assertEquals("010",     NamingConventionUtil.extractSubsystem(CONVENTIONNAME_011_110));
+        assertEquals("CWSE05",  NamingConventionUtil.extractSubsystem(CONVENTIONNAME_011_111));
+        assertEquals("010",     NamingConventionUtil.extractSubsystem(CONVENTIONNAME_111_110));
+        assertEquals("CWSE05",  NamingConventionUtil.extractSubsystem(CONVENTIONNAME_111_111));
+
+        assertEquals("CWSE05",  NamingConventionUtil.extractSubsystem(CONVENTIONNAME_011_111_SC1));
+        assertEquals("CWSE05",  NamingConventionUtil.extractSubsystem(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals("CWSE5",   NamingConventionUtil.extractSubsystem(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals("CWSE5",   NamingConventionUtil.extractSubsystem(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test of extraction of discipline from convention name.
+     */
+    @Test
+    public void extractDiscipline() {
+        assertNull(NamingConventionUtil.extractDiscipline(NULL));
+        assertNull(NamingConventionUtil.extractDiscipline(EMPTY));
+        assertNull(NamingConventionUtil.extractDiscipline(DUMMY));
+
+        assertEquals(NULL,      NamingConventionUtil.extractDiscipline(CONVENTIONNAME_010));
+        assertEquals(NULL,      NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011));
+
+        assertEquals("WtrC",    NamingConventionUtil.extractDiscipline(CONVENTIONNAME_010_111));
+        assertEquals("PwrC",    NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_110));
+        assertEquals("WtrC",    NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_111));
+        assertEquals("PwrC",    NamingConventionUtil.extractDiscipline(CONVENTIONNAME_111_110));
+        assertEquals("WtrC",    NamingConventionUtil.extractDiscipline(CONVENTIONNAME_111_111));
+
+        assertEquals("SC",      NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_111_SC1));
+        assertEquals("SC",      NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals("WTRC",    NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals("WTRC",    NamingConventionUtil.extractDiscipline(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test of extraction of device type from convention name.
+     */
+    @Test
+    public void extractDeviceType() {
+        assertNull(NamingConventionUtil.extractDeviceType(NULL));
+        assertNull(NamingConventionUtil.extractDeviceType(EMPTY));
+        assertNull(NamingConventionUtil.extractDeviceType(DUMMY));
+
+        assertEquals(NULL,      NamingConventionUtil.extractDeviceType(CONVENTIONNAME_010));
+        assertEquals(NULL,      NamingConventionUtil.extractDeviceType(CONVENTIONNAME_011));
+
+        assertEquals("EC",      NamingConventionUtil.extractDeviceType(CONVENTIONNAME_010_111));
+        assertEquals("PSChop",  NamingConventionUtil.extractDeviceType(CONVENTIONNAME_011_110));
+        assertEquals("EC",      NamingConventionUtil.extractDeviceType(CONVENTIONNAME_011_111));
+        assertEquals("PSChop",  NamingConventionUtil.extractDeviceType(CONVENTIONNAME_111_110));
+        assertEquals("EC",      NamingConventionUtil.extractDeviceType(CONVENTIONNAME_111_111));
+
+        assertEquals("EC",      NamingConventionUtil.extractDeviceType(CONVENTIONNAME_011_111_SC1));
+        assertEquals("IOC",     NamingConventionUtil.extractDeviceType(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals("EC",      NamingConventionUtil.extractDeviceType(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals("EC",      NamingConventionUtil.extractDeviceType(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test of extraction of instance index from convention name.
+     */
+    @Test
+    public void extractInstanceIndex() {
+        assertNull(NamingConventionUtil.extractInstanceIndex(NULL));
+        assertNull(NamingConventionUtil.extractInstanceIndex(EMPTY));
+        assertNull(NamingConventionUtil.extractInstanceIndex(DUMMY));
+
+        assertEquals(NULL,      NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_010));
+        assertEquals(NULL,      NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_011));
+
+        assertEquals("003",     NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_010_111));
+        assertEquals(NULL,      NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_011_110));
+        assertEquals("003",     NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_011_111));
+        assertEquals(NULL,      NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_111_110));
+        assertEquals("003",     NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_111_111));
+
+        assertEquals("003",     NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_011_111_SC1));
+        assertEquals("003",     NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals("3",       NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals("3",       NamingConventionUtil.extractInstanceIndex(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test of extraction of mnemonic path for system structure from convention name.
+     */
+    @Test
+    public void extractMnemonicPathSystemStructure() {
+        assertEquals(NULL,               NamingConventionUtil.extractMnemonicPathSystemStructure(NULL));
+        assertEquals(NULL,               NamingConventionUtil.extractMnemonicPathSystemStructure(EMPTY));
+        assertEquals(DUMMY,              NamingConventionUtil.extractMnemonicPathSystemStructure(DUMMY));
+
+        assertEquals(CONVENTIONNAME_010, NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_010));
+        assertEquals(CONVENTIONNAME_011, NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_011));
+        assertEquals(CONVENTIONNAME_111, NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_111));
+
+        assertEquals("CWL",              NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_010_111));
+        assertEquals("LEBT-010",         NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_011_110));
+        assertEquals("CWL-CWSE05",       NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_011_111));
+        assertEquals("Acc-LEBT-010",     NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_111_110));
+        assertEquals("DUMMY-CWL-CWSE05", NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_111_111));
+
+        assertEquals("CWL-CWSE05",       NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_011_111_SC1));
+        assertEquals("CWL-CWSE05",       NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals("CW1-CWSE5",        NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals("DUMMY-CW1-CWSE5",  NamingConventionUtil.extractMnemonicPathSystemStructure(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test of extraction of mnemonic path for device structure from convention name.
+     */
+    @Test
+    public void extractMnemonicPathDeviceStructure() {
+        assertEquals(NULL,          NamingConventionUtil.extractMnemonicPathDeviceStructure(NULL));
+        assertEquals(NULL,          NamingConventionUtil.extractMnemonicPathDeviceStructure(EMPTY));
+        assertEquals(NULL,          NamingConventionUtil.extractMnemonicPathDeviceStructure(DUMMY));
+
+        assertEquals(NULL,          NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_010));
+        assertEquals(NULL,          NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011));
+        assertEquals(NULL,          NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_111));
+
+        assertEquals("WtrC-EC",     NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_010_111));
+        assertEquals("PwrC-PSChop", NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_110));
+        assertEquals("WtrC-EC",     NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_111));
+        assertEquals("PwrC-PSChop", NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_111_110));
+        assertEquals("WtrC-EC",     NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_111_111));
+
+        assertEquals("SC-EC",       NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_111_SC1));
+        assertEquals("SC-IOC",      NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals("WTRC-EC",     NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals("WTRC-EC",     NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test to get index style from convention name.
+     */
+    @Test
+    public void getInstanceIndexStyleConventionName() {
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle("Mech-TDS"));
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle("Cryo-TDS"));
+
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle(NULL));
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle(EMPTY));
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle(DUMMY));
+
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_010));
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_011));
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_111));
+
+        assertEquals(NamingConventionUtil.DISCIPLINE_P_ID,       NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_010_111));
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_011_110));
+        assertEquals(NamingConventionUtil.DISCIPLINE_P_ID,       NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_011_111));
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_111_110));
+        assertEquals(NamingConventionUtil.DISCIPLINE_P_ID,       NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_111_111));
+
+        assertEquals(NamingConventionUtil.DISCIPLINE_P_ID,       NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_011_111_SC1));
+        assertEquals(NamingConventionUtil.DISCIPLINE_P_ID,       NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_011_111_SC2));
+
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_011_111_EQCLASS));
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test to get index style from discipline.
+     */
+    @Test
+    public void getInstanceIndexStyleDiscipline() {
+        Discipline discipline = new Discipline();
+
+        discipline.setMnemonic(NULL);
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle(discipline));
+        discipline.setMnemonic(EMPTY);
+        assertEquals(NULL, NamingConventionUtil.getInstanceIndexStyle(discipline));
+        discipline.setMnemonic(DUMMY);
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(discipline));
+
+        discipline.setMnemonic(ACC);
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(discipline));
+        discipline.setMnemonic(LEBT);
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(discipline));
+        discipline.setMnemonic(ZERO_ONE_ZERO);
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(discipline));
+
+        discipline.setMnemonic("Mech");
+        assertEquals(NamingConventionUtil.DISCIPLINE_SCIENTIFIC, NamingConventionUtil.getInstanceIndexStyle(discipline));
+        discipline.setMnemonic("Cryo");
+        assertEquals(NamingConventionUtil.DISCIPLINE_P_ID, NamingConventionUtil.getInstanceIndexStyle(discipline));
+        discipline.setMnemonic("SC");
+        assertEquals(NamingConventionUtil.DISCIPLINE_P_ID, NamingConventionUtil.getInstanceIndexStyle(discipline));
+    }
+
+    /**
+     * Test to check if discipline is PID.
+     */
+    @Test
+    public void isDisciplinePID() {
+        assertFalse(NamingConventionUtil.isDisciplinePID(NULL));
+        assertFalse(NamingConventionUtil.isDisciplinePID(EMPTY));
+        assertFalse(NamingConventionUtil.isDisciplinePID(DUMMY));
+
+        assertFalse(NamingConventionUtil.isDisciplinePID("Mech"));
+        assertTrue (NamingConventionUtil.isDisciplinePID("Cryo"));
+
+        assertFalse(NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_010)));
+        assertFalse(NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011)));
+        assertFalse(NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_111)));
+
+        assertTrue (NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_010_111)));
+        assertFalse(NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_110)));
+        assertTrue (NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_111)));
+        assertFalse(NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_111_110)));
+        assertTrue (NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_111_111)));
+
+        assertTrue (NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_111_SC1)));
+        assertTrue (NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_111_SC2)));
+
+        assertFalse(NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_011_111_EQCLASS)));
+        assertFalse(NamingConventionUtil.isDisciplinePID(NamingConventionUtil.extractDiscipline(CONVENTIONNAME_111_111_EQCLASS)));
+    }
+
+    /**
+     * Test to check if mnemonic path (device structure) is PID numeric.
+     */
+    @Test
+    public void isMnemonicPathPIDNumeric() {
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NULL));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(EMPTY));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(DUMMY));
+
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric("Mech"));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric("Cryo"));
+
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_010)));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011)));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_111)));
+
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_010_111)));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_110)));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_111)));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_111_110)));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_111_111)));
+
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_111_SC1)));
+        assertTrue (NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_111_SC2)));
+
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_011_111_EQCLASS)));
+        assertFalse(NamingConventionUtil.isMnemonicPathDeviceStructurePIDNumeric(NamingConventionUtil.extractMnemonicPathDeviceStructure(CONVENTIONNAME_111_111_EQCLASS)));
+    }
+
+    /**
+     * Test to check if convention name is offsite.
+     */
+    @Test
+    public void isOffsite() {
+        assertFalse(NamingConventionUtil.isOffsite(CONVENTIONNAME_010));
+        assertFalse(NamingConventionUtil.isOffsite(CONVENTIONNAME_011));
+
+        assertFalse(NamingConventionUtil.isOffsite(CONVENTIONNAME_010_111));
+        assertFalse(NamingConventionUtil.isOffsite(CONVENTIONNAME_011_110));
+        assertFalse(NamingConventionUtil.isOffsite(CONVENTIONNAME_011_111));
+        assertTrue (NamingConventionUtil.isOffsite(CONVENTIONNAME_111_110));
+        assertTrue (NamingConventionUtil.isOffsite(CONVENTIONNAME_111_111));
+
+        assertFalse(NamingConventionUtil.isOffsite(CONVENTIONNAME_011_111_SC1));
+        assertFalse(NamingConventionUtil.isOffsite(CONVENTIONNAME_011_111_SC2));
+
+        assertFalse(NamingConventionUtil.isOffsite(CONVENTIONNAME_011_111_EQCLASS));
+        assertTrue (NamingConventionUtil.isOffsite(CONVENTIONNAME_111_111_EQCLASS));
+    }
+
+    /**
+     * Test to check conversion of string (e.g. name) to mnemonic path.
+     */
+    @Test
+    public void string2MnemonicPath() {
+        String[] array = null;
+
+        array = NamingConventionUtil.string2MnemonicPath(null);
+        assertNull(array);
+
+        array = NamingConventionUtil.string2MnemonicPath("");
+        assertNotNull(array);
+        assertEquals(0, array.length);
+
+        array = NamingConventionUtil.string2MnemonicPath("A");
+        assertNotNull(array);
+        assertEquals(1, array.length);
+        assertEquals("A", array[0]);
+
+        array = NamingConventionUtil.string2MnemonicPath("A-B");
+        assertNotNull(array);
+        assertEquals(2, array.length);
+        assertEquals("A", array[0]);
+        assertEquals("B", array[1]);
+
+        array = NamingConventionUtil.string2MnemonicPath("A-B-C");
+        assertNotNull(array);
+        assertEquals(3, array.length);
+        assertEquals("A", array[0]);
+        assertEquals("B", array[1]);
+        assertEquals("C", array[2]);
+    }
+}
-- 
GitLab