From 5e8dafa4694df675c45fce8259a8ae82fc957a09 Mon Sep 17 00:00:00 2001
From: Lars Johansson <lars.johansson@ess.eu>
Date: Thu, 14 Jul 2022 15:45:59 +0200
Subject: [PATCH] Fix issues in REST API for names and structures and update
 integration tests

Fix issue for retrieve by name/uuid. Uuid with valid format but non-existing.
Fix issue for retrieve structure by parent uuid. No parent uuid for system group, discipline.
Add url encoding by default for integration tests.
Add and update integration tests for names and structures.
---
 .../rest/controller/StructuresController.java |   8 +-
 .../openepics/names/service/NamesService.java |  34 +--
 .../names/service/StructuresService.java      | 109 +++++---
 .../openepics/names/util/EncodingUtility.java |  77 ++++++
 .../org/openepics/names/util/URLUtility.java  | 198 ++++++++++++++
 .../org/openepics/names/docker/ITUtil.java    |   5 +-
 .../org/openepics/names/docker/NamesIT.java   |  89 +++++--
 .../names/docker/StructuresDeviceGroupIT.java |  58 ++++-
 .../names/docker/StructuresDeviceTypeIT.java  |  64 ++++-
 .../names/docker/StructuresDisciplineIT.java  |  48 ++++
 .../names/docker/StructuresSubsystemIT.java   |  80 +++++-
 .../names/docker/StructuresSystemGroupIT.java |  48 ++++
 .../names/docker/StructuresSystemIT.java      |  61 ++++-
 .../names/util/EncodingUtilityTest.java       | 246 ++++++++++++++++++
 .../openepics/names/util/URLUtilityTest.java  | 184 +++++++++++++
 15 files changed, 1215 insertions(+), 94 deletions(-)
 create mode 100644 src/main/java/org/openepics/names/util/EncodingUtility.java
 create mode 100644 src/main/java/org/openepics/names/util/URLUtility.java
 create mode 100644 src/test/java/org/openepics/names/util/EncodingUtilityTest.java
 create mode 100644 src/test/java/org/openepics/names/util/URLUtilityTest.java

diff --git a/src/main/java/org/openepics/names/rest/controller/StructuresController.java b/src/main/java/org/openepics/names/rest/controller/StructuresController.java
index 8bd76099..27965f40 100644
--- a/src/main/java/org/openepics/names/rest/controller/StructuresController.java
+++ b/src/main/java/org/openepics/names/rest/controller/StructuresController.java
@@ -142,11 +142,11 @@ public class StructuresController implements IStructures {
 
     @Override
     public ResponsePageStructureElements readStructures(Type type, Status[] statuses, Boolean deleted,
-            String uuid, String parentUuid, String name, String mnemonic, String mnemonicequivalence, String mnemonicpath, String description,
+            String uuid, String parentuuid, String name, String mnemonic, String mnemonicequivalence, String mnemonicpath, String description,
             FieldStructure orderBy, Boolean isAsc, Integer page, Integer pageSize) {
         try {
             return structuresService.readStructures(type, statuses, deleted,
-                    uuid, parentUuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
+                    uuid, parentuuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
                     orderBy, isAsc, page, pageSize);
         } catch (ServiceException e) {
             logService.logServiceException(LOGGER, Level.WARNING, e);
@@ -160,10 +160,10 @@ public class StructuresController implements IStructures {
 
     @Override
     public ResponseEntity<Resource> readStructuresDownload(Type type, Status[] statuses, Boolean deleted,
-            String uuid, String parentUuid, String name, String mnemonic, String mnemonicequivalence, String mnemonicpath, String description,
+            String uuid, String parentuuid, String name, String mnemonic, String mnemonicequivalence, String mnemonicpath, String description,
             FieldStructure orderBy, Boolean isAsc, Integer page, Integer pageSize) {
         ResponsePageStructureElements structureElements = readStructures(type, statuses, deleted,
-                uuid, parentUuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
+                uuid, parentuuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
                 orderBy, isAsc, page, pageSize);
         InputStreamResource isr = new InputStreamResource(ExcelUtil.structureElementsToExcel(structureElements));
         return ResponseEntity.ok()
diff --git a/src/main/java/org/openepics/names/service/NamesService.java b/src/main/java/org/openepics/names/service/NamesService.java
index f8fcec32..122be991 100644
--- a/src/main/java/org/openepics/names/service/NamesService.java
+++ b/src/main/java/org/openepics/names/service/NamesService.java
@@ -218,19 +218,19 @@ public class NamesService {
             String uuid, String name, String nameequivalence, String systemstructure, String devicestructure, String index, String description,
             Boolean includeHistory, FieldName orderBy, Boolean isAsc, Integer offset, Integer limit) {
 
-        LOGGER.log(Level.FINE, "readNames, deleted:            {0}", deleted);
-        LOGGER.log(Level.FINE, "readNames, uuid:               {0}", uuid);
-        LOGGER.log(Level.FINE, "readNames, name:               {0}", name);
-        LOGGER.log(Level.FINE, "readNames, nameequivalence:    {0}", nameequivalence);
-        LOGGER.log(Level.FINE, "readNames, systemstructure:    {0}", systemstructure);
-        LOGGER.log(Level.FINE, "readNames, devicestructure:    {0}", devicestructure);
-        LOGGER.log(Level.FINE, "readNames, index:              {0}", index);
-        LOGGER.log(Level.FINE, "readNames, description:        {0}", description);
-        LOGGER.log(Level.FINE, "readNames, includeHistory:     {0}", includeHistory);
-        LOGGER.log(Level.FINE, "readNames, orderBy:            {0}", orderBy);
-        LOGGER.log(Level.FINE, "readNames, isAsc:              {0}", isAsc);
-        LOGGER.log(Level.FINE, "readNames, offset:             {0}", offset);
-        LOGGER.log(Level.FINE, "readNames, limit:              {0}", limit);
+        LOGGER.log(Level.FINE, "readNames, deleted:         {0}", deleted);
+        LOGGER.log(Level.FINE, "readNames, uuid:            {0}", uuid);
+        LOGGER.log(Level.FINE, "readNames, name:            {0}", name);
+        LOGGER.log(Level.FINE, "readNames, nameequivalence: {0}", nameequivalence);
+        LOGGER.log(Level.FINE, "readNames, systemstructure: {0}", systemstructure);
+        LOGGER.log(Level.FINE, "readNames, devicestructure: {0}", devicestructure);
+        LOGGER.log(Level.FINE, "readNames, index:           {0}", index);
+        LOGGER.log(Level.FINE, "readNames, description:     {0}", description);
+        LOGGER.log(Level.FINE, "readNames, includeHistory:  {0}", includeHistory);
+        LOGGER.log(Level.FINE, "readNames, orderBy:         {0}", orderBy);
+        LOGGER.log(Level.FINE, "readNames, isAsc:           {0}", isAsc);
+        LOGGER.log(Level.FINE, "readNames, offset:          {0}", offset);
+        LOGGER.log(Level.FINE, "readNames, limit:           {0}", limit);
 
         // validate input
         //     queryFields and queryValues
@@ -258,14 +258,14 @@ public class NamesService {
         }
 
         ResponsePageNameElements response = new ResponsePageNameElements(nameElements, totalCount, nameElements.size(), offset, limit);
-        LOGGER.log(Level.FINE, "readNames, response:           {0}", response);
+        LOGGER.log(Level.FINE, "readNames, response:        {0}", response);
         return response;
     }
 
     public ResponsePageNameElements readNames(String name,
             FieldName orderBy, Boolean isAsc, Integer offset, Integer limit) {
 
-        LOGGER.log(Level.FINE, "readNames, name:              {0}", name);
+        LOGGER.log(Level.FINE, "readNames, name: {0}", name);
 
         // validate input
         //     name or uuid
@@ -293,7 +293,7 @@ public class NamesService {
                     orderBy, isAsc, offset, limit);
         }
 
-        return new ResponsePageNameElements();
+        return new ResponsePageNameElements(nameElements, Long.valueOf(nameElements.size()), nameElements.size(), offset, limit);
     }
 
     public ResponsePageNameElements readNamesSystemStructure(String mnemonicpath,
@@ -340,7 +340,7 @@ public class NamesService {
 
     public ResponsePageNameElements readNamesHistory(String uuid,
             FieldName orderBy, Boolean isAsc, Integer offset, Integer limit) {
-        LOGGER.log(Level.FINE, "readNamesHistory, uuid:              {0}", uuid);
+        LOGGER.log(Level.FINE, "readNamesHistory, uuid: {0}", uuid);
 
         // note
         //     HolderIRepositories and HolderSystemDeviceStructure may or may not be used for preparation of what to return
diff --git a/src/main/java/org/openepics/names/service/StructuresService.java b/src/main/java/org/openepics/names/service/StructuresService.java
index 95eef282..181173c3 100644
--- a/src/main/java/org/openepics/names/service/StructuresService.java
+++ b/src/main/java/org/openepics/names/service/StructuresService.java
@@ -274,25 +274,25 @@ public class StructuresService {
             Boolean includeHistory, FieldStructure orderBy, Boolean isAsc, Integer offset, Integer limit,
             StructureChoice structureChoice) {
 
-        LOGGER.log(Level.FINE, "readStructures, type:                   {0}", type);
-        LOGGER.log(Level.FINE, "readStructures, statuses.length:        {0}", String.valueOf(statuses != null ? statuses.length : "null"));
-        LOGGER.log(Level.FINE, "readStructures, deleted:                {0}", deleted);
-        LOGGER.log(Level.FINE, "readStructures, uuid:                   {0}", uuid);
-        LOGGER.log(Level.FINE, "readStructures, parentUuid:             {0}", parentUuid);
-        LOGGER.log(Level.FINE, "readStructures, name:                   {0}", name);
-        LOGGER.log(Level.FINE, "readStructures, mnemonic:               {0}", mnemonic);
-        LOGGER.log(Level.FINE, "readStructures, mnemonicequivalence:    {0}", mnemonicequivalence);
-        LOGGER.log(Level.FINE, "readStructures, mnemonicpath:           {0}", mnemonicpath);
-        LOGGER.log(Level.FINE, "readStructures, description:            {0}", description);
-        LOGGER.log(Level.FINE, "readStructures, includeHistory:         {0}", includeHistory);
-        LOGGER.log(Level.FINE, "readStructures, orderBy:                {0}", orderBy);
-        LOGGER.log(Level.FINE, "readStructures, isAsc:                  {0}", isAsc);
-        LOGGER.log(Level.FINE, "readStructures, offset:                 {0}", offset);
-        LOGGER.log(Level.FINE, "readStructures, limit:                  {0}", limit);
-        LOGGER.log(Level.FINE, "readStructures, structureChoice:        {0}", structureChoice);
+        LOGGER.log(Level.FINE, "readStructures, type:                {0}", type);
+        LOGGER.log(Level.FINE, "readStructures, statuses.length:     {0}", String.valueOf(statuses != null ? statuses.length : "null"));
+        LOGGER.log(Level.FINE, "readStructures, deleted:             {0}", deleted);
+        LOGGER.log(Level.FINE, "readStructures, uuid:                {0}", uuid);
+        LOGGER.log(Level.FINE, "readStructures, parentUuid:          {0}", parentUuid);
+        LOGGER.log(Level.FINE, "readStructures, name:                {0}", name);
+        LOGGER.log(Level.FINE, "readStructures, mnemonic:            {0}", mnemonic);
+        LOGGER.log(Level.FINE, "readStructures, mnemonicequivalence: {0}", mnemonicequivalence);
+        LOGGER.log(Level.FINE, "readStructures, mnemonicpath:        {0}", mnemonicpath);
+        LOGGER.log(Level.FINE, "readStructures, description:         {0}", description);
+        LOGGER.log(Level.FINE, "readStructures, includeHistory:      {0}", includeHistory);
+        LOGGER.log(Level.FINE, "readStructures, orderBy:             {0}", orderBy);
+        LOGGER.log(Level.FINE, "readStructures, isAsc:               {0}", isAsc);
+        LOGGER.log(Level.FINE, "readStructures, offset:              {0}", offset);
+        LOGGER.log(Level.FINE, "readStructures, limit:               {0}", limit);
+        LOGGER.log(Level.FINE, "readStructures, structureChoice:     {0}", structureChoice);
         if (statuses != null && statuses.length > 0) {
             for (Status status : statuses) {
-                LOGGER.log(Level.FINE, "readStructures, status:                 {0}", status);
+                LOGGER.log(Level.FINE, "readStructures, status:              {0}", status);
             }
         }
 
@@ -317,13 +317,20 @@ public class StructuresService {
         final List<StructureElement> structureElements = Lists.newArrayList();
         Long totalCount = null;
         if (Type.SYSTEMGROUP.equals(type)) {
-            List<SystemGroup> systemGroups = holderRepositories.getSystemGroupRepository().readSystemGroups(statuses, deleted,
-                    uuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
-                    includeHistory, orderBy, isAsc, offset, limit);
-            totalCount = holderRepositories.getSystemGroupRepository().countSystemGroups(statuses, deleted,
-                    uuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
-                    includeHistory);
-            LOGGER.log(Level.FINE, "readStructures, systemGroups.size:      {0}", systemGroups.size());
+            // system group has no parent uuid
+            List<SystemGroup> systemGroups = null;
+            if (StringUtils.isEmpty(parentUuid)) {
+                systemGroups = holderRepositories.getSystemGroupRepository().readSystemGroups(statuses, deleted,
+                        uuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
+                        includeHistory, orderBy, isAsc, offset, limit);
+                totalCount = holderRepositories.getSystemGroupRepository().countSystemGroups(statuses, deleted,
+                        uuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
+                        includeHistory);
+            } else {
+                systemGroups = Lists.newArrayList();
+                totalCount = 0L;
+            }
+            LOGGER.log(Level.FINE, "readStructures, systemGroups.size:   {0}", systemGroups.size());
             structureElements.addAll(StructureElementUtil.getStructureElementsForSystemGroups(systemGroups, holder, structureChoice));
         } else if (Type.SYSTEM.equals(type)) {
             List<System> systems = holderRepositories.getSystemRepository().readSystems(statuses, deleted,
@@ -332,7 +339,7 @@ public class StructuresService {
             totalCount = holderRepositories.getSystemRepository().countSystems(statuses, deleted,
                     uuid, parentUuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
                     includeHistory);
-            LOGGER.log(Level.FINE, "readStructures, systems.size:           {0}", systems.size());
+            LOGGER.log(Level.FINE, "readStructures, systems.size:        {0}", systems.size());
             structureElements.addAll(StructureElementUtil.getStructureElementsForSystems(systems, holder, structureChoice));
         } else if (Type.SUBSYSTEM.equals(type)) {
             List<Subsystem> subsystems = holderRepositories.getSubsystemRepository().readSubsystems(statuses, deleted,
@@ -341,16 +348,23 @@ public class StructuresService {
             totalCount = holderRepositories.getSubsystemRepository().countSubsystems(statuses, deleted,
                     uuid, parentUuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
                     includeHistory);
-            LOGGER.log(Level.FINE, "readStructures, subsystems.size:        {0}", subsystems.size());
+            LOGGER.log(Level.FINE, "readStructures, subsystems.size:     {0}", subsystems.size());
             structureElements.addAll(StructureElementUtil.getStructureElementsForSubsystems(subsystems, holder, structureChoice));
         } else if (Type.DISCIPLINE.equals(type)) {
-            List<Discipline> disciplines = holderRepositories.getDisciplineRepository().readDisciplines(statuses, deleted,
-                    uuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
-                    includeHistory, orderBy, isAsc, offset, limit);
-            totalCount = holderRepositories.getDisciplineRepository().countDisciplines(statuses, deleted,
-                    uuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
-                    includeHistory);
-            LOGGER.log(Level.FINE, "readStructures, disciplines.size:       {0}", disciplines.size());
+            // discipline has no parent uuid
+            List<Discipline> disciplines = null;
+            if (StringUtils.isEmpty(parentUuid)) {
+                disciplines = holderRepositories.getDisciplineRepository().readDisciplines(statuses, deleted,
+                        uuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
+                        includeHistory, orderBy, isAsc, offset, limit);
+                totalCount = holderRepositories.getDisciplineRepository().countDisciplines(statuses, deleted,
+                        uuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
+                        includeHistory);
+            } else {
+                disciplines = Lists.newArrayList();
+                totalCount = 0L;
+            }
+            LOGGER.log(Level.FINE, "readStructures, disciplines.size:    {0}", disciplines.size());
             structureElements.addAll(StructureElementUtil.getStructureElementsForDisciplines(disciplines, holder, structureChoice));
         } else if (Type.DEVICEGROUP.equals(type)) {
             List<DeviceGroup> deviceGroups = holderRepositories.getDeviceGroupRepository().readDeviceGroups(statuses, deleted,
@@ -359,7 +373,7 @@ public class StructuresService {
             totalCount = holderRepositories.getDeviceGroupRepository().countDeviceGroups(statuses, deleted,
                     uuid, parentUuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
                     includeHistory);
-            LOGGER.log(Level.FINE, "readStructures, deviceGroups.size:      {0}", deviceGroups.size());
+            LOGGER.log(Level.FINE, "readStructures, deviceGroups.size:   {0}", deviceGroups.size());
             structureElements.addAll(StructureElementUtil.getStructureElementsForDeviceGroups(deviceGroups, holder, structureChoice));
         } else if (Type.DEVICETYPE.equals(type)) {
             List<DeviceType> deviceTypes = holderRepositories.getDeviceTypeRepository().readDeviceTypes(statuses, deleted,
@@ -368,12 +382,12 @@ public class StructuresService {
             totalCount = holderRepositories.getDeviceTypeRepository().countDeviceTypes(statuses, deleted,
                     uuid, parentUuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description,
                     includeHistory);
-            LOGGER.log(Level.FINE, "readStructures, deviceTypes.size:       {0}", deviceTypes.size());
+            LOGGER.log(Level.FINE, "readStructures, deviceTypes.size:    {0}", deviceTypes.size());
             structureElements.addAll(StructureElementUtil.getStructureElementsForDeviceTypes(deviceTypes, holder, structureChoice));
         }
 
         ResponsePageStructureElements response = new ResponsePageStructureElements(structureElements, totalCount, structureElements.size(), offset, limit);
-        LOGGER.log(Level.FINE, "readStructures, response:           {0}", response);
+        LOGGER.log(Level.FINE, "readStructures, response:            {0}", response);
         return response;
     }
 
@@ -388,8 +402,8 @@ public class StructuresService {
         // return
         //     structure elements for structures
 
-        LOGGER.log(Level.FINE, "readStructuresChildren, type:                   {0}", type);
-        LOGGER.log(Level.FINE, "readStructuresChildren, uuid:                   {0}", uuid);
+        LOGGER.log(Level.FINE, "readStructuresChildren, type: {0}", type);
+        LOGGER.log(Level.FINE, "readStructuresChildren, uuid: {0}", uuid);
 
         // validate input
         ValidateUtil.validateInputType(type);
@@ -437,6 +451,8 @@ public class StructuresService {
         // return
         //     structure elements for structures
 
+        LOGGER.log(Level.FINE, "readStructuresMnemonic, mnemonic: {0}", mnemonic);
+
         // validate input
         ValidateUtil.validateInputMnemonic(mnemonic);
 
@@ -471,6 +487,8 @@ public class StructuresService {
         // return
         //     structure elements for structures
 
+        LOGGER.log(Level.FINE, "readStructuresMnemonicpath, mnemonicpath: {0}", mnemonicpath);
+
         // validate input
         ValidateUtil.validateInputMnemonic(mnemonicpath);
 
@@ -515,6 +533,9 @@ public class StructuresService {
         // return
         //     structure elements for structures
 
+        LOGGER.log(Level.FINE, "readStructuresHistory, uuid: {0}", uuid);
+        LOGGER.log(Level.FINE, "readStructuresHistory, type: {0}", type);
+
         // validate input
         ValidateUtil.validateInputUuid(uuid);
 
@@ -587,6 +608,8 @@ public class StructuresService {
         // do
         //     exists
 
+        LOGGER.log(Level.FINE, "equivalenceMnemonic, mnemonic: {0}", mnemonic);
+
         // validate input
         ValidateUtil.validateInputMnemonic(mnemonic);
 
@@ -599,6 +622,8 @@ public class StructuresService {
         // do
         //     exists
 
+        LOGGER.log(Level.FINE, "existsStructure, mnemonicpath: {0}", mnemonicpath);
+
         // validate input
         ValidateUtil.validateInputType(type);
         ValidateUtil.validateInputMnemonicpath(mnemonicpath);
@@ -638,6 +663,8 @@ public class StructuresService {
         // validate data
         //     not exists
 
+        LOGGER.log(Level.FINE, "isValidToCreateStructure, mnemonicpath: {0}", mnemonicpath);
+
         // validate input
         ValidateUtil.validateInputType(type);
         ValidateUtil.validateInputMnemonicpath(mnemonicpath);
@@ -1183,7 +1210,7 @@ public class StructuresService {
                 if (!StringUtils.isEmpty(systemGroup.getMnemonic())) {
                     NameElementCommand nameElement = new NameElementCommand(null, systemGroup.getUuid(), null, null, SYSTEM_STRUCTURE_ONLY, null);
                     NameElement createdNameElement = namesService.createName(nameElement, holder, processed, processedBy);
-                    LOGGER.log(Level.FINE, "approveStructures, nameElement created, name:      {0}", createdNameElement.getName());
+                    LOGGER.log(Level.FINE, "approveStructures, nameElement created, name:  {0}", createdNameElement.getName());
                 }
 
                 // add
@@ -1221,7 +1248,7 @@ public class StructuresService {
                 if (!StringUtils.isEmpty(system.getMnemonic())) {
                     NameElementCommand nameElement = new NameElementCommand(null, system.getUuid(), null, null, SYSTEM_STRUCTURE_ONLY, null);
                     NameElement createdNameElement = namesService.createName(nameElement, holder, processed, processedBy);
-                    LOGGER.log(Level.FINE, "approveStructures, nameElement created, name:      {0}", createdNameElement.getName());
+                    LOGGER.log(Level.FINE, "approveStructures, nameElement created, name:  {0}", createdNameElement.getName());
                 }
 
                 // add
@@ -1259,7 +1286,7 @@ public class StructuresService {
                 if (!StringUtils.isEmpty(subsystem.getMnemonic())) {
                     NameElementCommand nameElement = new NameElementCommand(null, subsystem.getUuid(), null, null, SYSTEM_STRUCTURE_ONLY, null);
                     NameElement createdNameElement = namesService.createName(nameElement, holder, processed, processedBy);
-                    LOGGER.log(Level.FINE, "approveStructures, nameElement created, name:      {0}", createdNameElement.getName());
+                    LOGGER.log(Level.FINE, "approveStructures, nameElement created, name:  {0}", createdNameElement.getName());
                 }
 
                 // add
diff --git a/src/main/java/org/openepics/names/util/EncodingUtility.java b/src/main/java/org/openepics/names/util/EncodingUtility.java
new file mode 100644
index 00000000..578a178d
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/EncodingUtility.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 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.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+/**
+ * Utility class for encoding a value according to encoding scheme.
+ *
+ * @author Lars Johansson
+ *
+ * @see EncodingUtility#ENCODING_SCHEME
+ */
+public class EncodingUtility {
+
+    public static final String ENCODING_SCHEME = "UTF-8";
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private EncodingUtility() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    /**
+     * Encode a <code>String</code> and return the encoded value.
+     *
+     * @param s the string to encode
+     * @return the encoded value
+     *
+     * @see EncodingUtility#ENCODING_SCHEME
+     * @see URLEncoder#encode(String, String)
+     */
+    public static String encode(String s) {
+        try {
+            return URLEncoder.encode(s, ENCODING_SCHEME);
+        } catch (UnsupportedEncodingException e) {
+            return s;
+        }
+    }
+
+    /**
+     * Decode a <code>String</code> and return the decoded value.
+     *
+     * @param s the string to decode
+     * @return the decoded value
+     *
+     * @see EncodingUtility#ENCODING_SCHEME
+     * @see URLDecoder#decode(String, String)
+     */
+    public static String decode(String s) {
+        try {
+            return URLDecoder.decode(s, ENCODING_SCHEME);
+        } catch (UnsupportedEncodingException e) {
+            return s;
+        }
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/util/URLUtility.java b/src/main/java/org/openepics/names/util/URLUtility.java
new file mode 100644
index 00000000..d0a115a7
--- /dev/null
+++ b/src/main/java/org/openepics/names/util/URLUtility.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018 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.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Utility class for URL handling, e.g. encoding URL.
+ *
+ * @author Lars Johansson
+ *
+ * @see EncodingUtility
+ */
+public class URLUtility {
+
+    /**
+     * / corresponds to Unicode \u002F
+     */
+    private static final String DELIMITER_PATH = "\u002F";
+    /**
+     * ? corresponds to Unicode \u003F
+     */
+    private static final String DELIMITER_PATH_QUERY = "\u003F";
+    /**
+     * & corresponds to Unicode \u003F
+     */
+    private static final String DELIMITER_ATTRIBUTES_VALUES = "\u0026";
+    /**
+     * = corresponds to Unicode \u003D
+     */
+    private static final String DELIMITER_ATTRIBUTE_VALUE = "\u003D";
+
+    private static final Pattern PATTERN_DELIMITER_PATH_QUERY =
+            Pattern.compile("\\" + DELIMITER_PATH_QUERY);
+    private static final Pattern PATTERN_DELIMITER_ATTRIBUTES_VALUES =
+            Pattern.compile("\\" + DELIMITER_ATTRIBUTES_VALUES);
+    private static final Pattern PATTERN_DELIMITER_ATTRIBUTE_VALUE =
+            Pattern.compile("\\" + DELIMITER_ATTRIBUTE_VALUE);
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private URLUtility() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    /**
+     * Encode a URL and return the encoded value.
+     *
+     * <p>
+     * Note that all or parts of URL may be encoded. In case of attributes, attribute values but not names are to be encoded.
+     * There are special characters that are used to separate parts of URL. Such characters are / ? & =
+     * </p>
+     *
+     * <br/> Different URLs
+     * <ul>
+     * <li> a           </li>
+     * <li> a/b         </li>
+     * <li> a/b?c       </li>
+     * <li> a/b?c=d     </li>
+     * <li> a/b?c=d&e=f </li>
+     * <li> ...         </li>
+     * </ul>
+     *
+     * <p>
+     *     Example a.
+     *     <ul>
+     *     <li>a is encoded</li>
+     *     </ul>
+     * </p>
+     * <p>
+     *     Example a/b.
+     *     <li>a is not encoded</li>
+     *     <li>b is encoded</li>
+     * </p>
+     * <p>
+     *     Example a/b?c.
+     *     <li>a is not encoded</li>
+     *     <li>b is encoded</li>
+     *     <li>c is encoded</li>
+     * </p>
+     * <p>
+     *     Example a/b?c=d.
+     *     <li>a is not encoded</li>
+     *     <li>b is encoded</li>
+     *     <li>c is not encoded</li>
+     *     <li>d is encoded</li>
+     * </p>
+     * <p>
+     *     Example a/b?c=d&e=f.
+     *     <li>a is not encoded</li>
+     *     <li>b is encoded</li>
+     *     <li>c is not encoded</li>
+     *     <li>d is encoded</li>
+     *     <li>e is not encoded</li>
+     *     <li>f is encoded</li>
+     * </p>
+     *
+     * <p>
+     * Example 1. For <code>abc.xhtml?attribute1=value1&amp;attribute2=value2</code>, it corresponds to b?c=d&e=f above.
+     * Then <code>abc.xhtml</code>, <code>value1</code> and <code>value2</code> are to be encoded, not other parts of url.
+     * <7p>
+     *
+     * <p>
+     * Example 2. For <code>cable-types.xhtml?cableTypeName=1C20RG-58HV+ 2C20</code>, it corresponds to b?c=d above.
+     * Then <code>cable-types.xhtml</code> and <code>1C20RG-58HV+ 2C20</code> is to be encoded, not other parts of url.
+     * </p>
+     *
+     * @param url a url
+     * @return the encoded value
+     *
+     * @see EncodingUtility#ENCODING_SCHEME
+     * @see EncodingUtility#encode(String)
+     * @see EncodingUtility#decode(String)
+     */
+    public static String encodeURL(String url) {
+        if (url == null)
+            return url;
+
+        // not trim url
+
+        // start prepare return value
+        StringBuilder encodedURL = new StringBuilder();
+
+        String path0 = null;
+        String path1 = null;
+
+        // split path on last DELIMITER_PATH
+        String reverseUrl = StringUtils.reverse(url);
+        int index = reverseUrl.indexOf(DELIMITER_PATH);
+        if (index == -1) {
+            path0 = null;
+            path1 = url;
+        } else {
+            path0 = StringUtils.reverse(reverseUrl.substring(index + 1));
+            path1 = StringUtils.reverse(reverseUrl.substring(0, index));
+            encodedURL.append(path0);
+            encodedURL.append(DELIMITER_PATH);
+        }
+
+      // split path and query
+      String[] pathQuery = PATTERN_DELIMITER_PATH_QUERY.split(path1, 2);
+      if (pathQuery.length != 2) {
+          encodedURL.append(EncodingUtility.encode(path1));
+          return encodedURL.toString();
+      }
+      encodedURL.append(pathQuery[0]);
+      encodedURL.append(DELIMITER_PATH_QUERY);
+
+        // split attribute-value pairs
+        String[] attributesValues = PATTERN_DELIMITER_ATTRIBUTES_VALUES.split(pathQuery[1]);
+
+        // loop through attributes_values, encode values
+        for (String pair : attributesValues) {
+            // split attribute and value
+            String[] attributeValue = PATTERN_DELIMITER_ATTRIBUTE_VALUE.split(pair, 2);
+
+            if (attributeValue.length == 1) {
+                // not encode attribute
+                encodedURL.append(EncodingUtility.encode(attributeValue[0]));
+                encodedURL.append(DELIMITER_ATTRIBUTES_VALUES);
+            } else {
+                // encode value
+              encodedURL.append(attributeValue[0]);
+              encodedURL.append(DELIMITER_ATTRIBUTE_VALUE);
+              encodedURL.append(EncodingUtility.encode(attributeValue[1]));
+              encodedURL.append(DELIMITER_ATTRIBUTES_VALUES);
+            }
+        }
+
+        // remove trailing delimiter
+        int length = encodedURL.length();
+        if (encodedURL.substring(length - 1).equals(DELIMITER_ATTRIBUTES_VALUES)) {
+            encodedURL.setLength(length - 1);
+        }
+
+        return encodedURL.toString();
+    }
+
+}
diff --git a/src/test/java/org/openepics/names/docker/ITUtil.java b/src/test/java/org/openepics/names/docker/ITUtil.java
index ec376d2d..400e1bc3 100644
--- a/src/test/java/org/openepics/names/docker/ITUtil.java
+++ b/src/test/java/org/openepics/names/docker/ITUtil.java
@@ -35,6 +35,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.openepics.names.rest.beans.response.Response;
 import org.openepics.names.rest.beans.response.ResponseBoolean;
 import org.openepics.names.rest.beans.response.ResponseBooleanList;
+import org.openepics.names.util.URLUtility;
 
 /**
  * Utility class to help (Docker) integration tests for Naming and PostgreSQL.
@@ -104,7 +105,9 @@ public class ITUtil {
      * @throws IOException
      */
     static String[] doGetJson(String spec) throws IOException {
-        URL url = new URL(spec);
+        // note that URL is encoded
+
+        URL url = new URL(URLUtility.encodeURL(spec));
         HttpURLConnection con = (HttpURLConnection) url.openConnection();
         int responseCode = con.getResponseCode();
 
diff --git a/src/test/java/org/openepics/names/docker/NamesIT.java b/src/test/java/org/openepics/names/docker/NamesIT.java
index 799def82..77f45e50 100644
--- a/src/test/java/org/openepics/names/docker/NamesIT.java
+++ b/src/test/java/org/openepics/names/docker/NamesIT.java
@@ -790,38 +790,81 @@ class NamesIT {
         responseNameElement = ITUtilNameElement.assertDelete(nameElement8);
 
         try {
-            // read
-
+            // read & search
+            //     deleted, uuid, name, nameequivalence, systemstructure, devicestructure, index, description
+            //     combination
             ITUtilNameElement.assertRead("", 8, -1);
 
-            ITUtilNameElement.assertRead("?uuid=" + uuid.toString(),   1);
-            ITUtilNameElement.assertRead("?nameequivalence=RFQ-10%25", 8, -1);
-            ITUtilNameElement.assertRead("?nameequivalence=RFQ-10%25&devicestructure=EMR-FS", 6, -1);
-            ITUtilNameElement.assertRead("?index=003", 1);
-
             ITUtilNameElement.assertRead("?deleted=false", 6, -1);
             ITUtilNameElement.assertRead("?deleted=true",  2, -1);
 
-            ITUtilNameElement.assertRead("/RFQ-010:EMR-FS-005",  1);
-            ITUtilNameElement.assertRead("/RFQ-010:EMR-FS-0",    0);
-            ITUtilNameElement.assertRead("/RFQ-010:EMR-FS-0__",  6, -1);
-            ITUtilNameElement.assertRead("/RFQ-010:EMR-FS-0%25", 6, -1);
+            ITUtilNameElement.assertRead("?uuid=" + deviceTypeFS.toString(), 0);
+            ITUtilNameElement.assertRead("?uuid=" + uuid.toString(),         1);
 
-            ITUtilNameElement.assertRead("/systemstructure/RFQ-010",  6, -1);
-            ITUtilNameElement.assertRead("/systemstructure/RFQ-0",    0);
-            ITUtilNameElement.assertRead("/systemstructure/RFQ-0__",  6, -1);
-            ITUtilNameElement.assertRead("/systemstructure/RFQ-N1U1", 1);
+            ITUtilNameElement.assertRead("?name=RFQ-010:EMR-FS-005",  1);
+            ITUtilNameElement.assertRead("?name=RFQ-010%",            8, -1);
+            ITUtilNameElement.assertRead("?name=RFQ-10%",             0);
 
-            ITUtilNameElement.assertRead("/devicestructure/EMR-FS", 6, -1);
-            ITUtilNameElement.assertRead("/devicestructure/EMR-F",  0);
-            ITUtilNameElement.assertRead("/devicestructure/EMR-F_", 6, -1);
-            ITUtilNameElement.assertRead("/devicestructure/EMR-TT", 0);
+            ITUtilNameElement.assertRead("?nameequivalence=RFQ-10%",  8, -1);
 
-            // history
+            ITUtilNameElement.assertRead("?systemstructure=RFQ-010",  6, -1);
+            ITUtilNameElement.assertRead("?systemstructure=RFQ-0",    0);
+            ITUtilNameElement.assertRead("?systemstructure=RFQ-0__",  6, -1);
+            ITUtilNameElement.assertRead("?systemstructure=RFQ-N1U1", 1);
+
+            ITUtilNameElement.assertRead("?devicestructure=EMR-FS",   6, -1);
+            ITUtilNameElement.assertRead("?devicestructure=EMR-F",    0);
+            ITUtilNameElement.assertRead("?devicestructure=EMR-F_",   6, -1);
+            ITUtilNameElement.assertRead("?devicestructure=EMR-TT",   0);
 
-            ITUtilNameElement.assertRead("/history/" + systemRFQ.toString(), 0);
-            ITUtilNameElement.assertRead("/history/" + uuid.toString(),      3);
-            ITUtilNameElement.assertRead("/history/" + uuid2.toString(),     1);
+            ITUtilNameElement.assertRead("?index=003", 1);
+
+            ITUtilNameElement.assertRead("?description=description",               7, -1);
+            ITUtilNameElement.assertRead("?description=%description%",             8, -1);
+            ITUtilNameElement.assertRead("?description=updated description",       0, -1);
+            ITUtilNameElement.assertRead("?description=updated description%",      1, -1);
+            ITUtilNameElement.assertRead("?description=updated description again", 1);
+
+            ITUtilNameElement.assertRead("?nameequivalence=RFQ-10%&devicestructure=EMR-FS", 6, -1);
+
+            // name or uuid
+            //     /{name}
+            ITUtilNameElement.assertRead("/" + systemGroupAcc.toString(), 0);
+            ITUtilNameElement.assertRead("/" + systemRFQ.toString(),      0);
+            ITUtilNameElement.assertRead("/" + subsystem010.toString(),   0);
+            ITUtilNameElement.assertRead("/" + disciplineEMR.toString(),  0);
+            ITUtilNameElement.assertRead("/" + deviceGroupEMR.toString(), 0);
+            ITUtilNameElement.assertRead("/" + deviceTypeFS.toString(),   0);
+            ITUtilNameElement.assertRead("/" + uuid.toString(),           1);
+            ITUtilNameElement.assertRead("/RFQ-010:EMR-FS-001",           1);
+            ITUtilNameElement.assertRead("/RFQ-010:EMR-FS-0",             0);
+            ITUtilNameElement.assertRead("/RFQ-010:EMR-FS-0__",           6, -1);
+            ITUtilNameElement.assertRead("/RFQ-010:EMR-FS-0%",            6, -1);
+
+            // system structure mnemonic path
+            //     /systemstructure/{mnemonicpath}
+            ITUtilNameElement.assertRead("/systemstructure/RFQ-010",      6, -1);
+            ITUtilNameElement.assertRead("/systemstructure/RFQ-0",        0);
+            ITUtilNameElement.assertRead("/systemstructure/RFQ-0__",      6, -1);
+            ITUtilNameElement.assertRead("/systemstructure/RFQ-N1U1",     1);
+
+            // device structure mnemonic path
+            //     /devicestructure/{mnemonicpath}
+            ITUtilNameElement.assertRead("/devicestructure/EMR-FS",       6, -1);
+            ITUtilNameElement.assertRead("/devicestructure/EMR-F",        0);
+            ITUtilNameElement.assertRead("/devicestructure/EMR-F_",       6, -1);
+            ITUtilNameElement.assertRead("/devicestructure/EMR-TT",       0);
+
+            // history
+            //     /history/{uuid}
+            ITUtilNameElement.assertRead("/history/" + systemGroupAcc.toString(), 0);
+            ITUtilNameElement.assertRead("/history/" + systemRFQ.toString(),      0);
+            ITUtilNameElement.assertRead("/history/" + subsystem010.toString(),   0);
+            ITUtilNameElement.assertRead("/history/" + disciplineEMR.toString(),  0);
+            ITUtilNameElement.assertRead("/history/" + deviceGroupEMR.toString(), 0);
+            ITUtilNameElement.assertRead("/history/" + deviceTypeFS.toString(),   0);
+            ITUtilNameElement.assertRead("/history/" + uuid.toString(),           3);
+            ITUtilNameElement.assertRead("/history/" + uuid2.toString(),          1);
         } catch (Exception e) {
             fail();
         }
diff --git a/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java b/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
index 297b399d..d6de272f 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
@@ -1773,6 +1773,10 @@ class StructuresDeviceGroupIT {
             // from first structure element
             assertNotNull(uuid);
 
+            // read & search
+            //     /{type}
+            //     type, statuses, deleted, uuid, parentuuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            //     combination
             ITUtilStructureElement.assertRead("/DEVICEGROUP?mnemonicpath=Di2",                                                  30);
             ITUtilStructureElement.assertRead("/DEVICEGROUP?statuses=PENDING&mnemonicpath=Di2",                                  5);
             ITUtilStructureElement.assertRead("/DEVICEGROUP?statuses=APPROVED&mnemonicpath=Di2",                                20);
@@ -1794,10 +1798,58 @@ class StructuresDeviceGroupIT {
             ITUtilStructureElement.assertRead("/DEVICEGROUP?deleted=true&statuses=REJECTED&mnemonicpath=Di2",                    5);
             ITUtilStructureElement.assertRead("/DEVICEGROUP?deleted=true&statuses=PENDING&statuses=APPROVED&mnemonicpath=Di2",  10);
 
-            ITUtilStructureElement.assertRead("/children/DEVICEGROUP/" + uuid.toString(),          0);
-            ITUtilStructureElement.assertRead("/children/DISCIPLINE/" + disciplineUuid.toString(), 1, -1);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?uuid=" + discipline2Uuid.toString(),       0);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?uuid=" + uuid.toString(),                  1);
+
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?parentuuid=" + discipline2Uuid.toString(), 45, -1);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?parentuuid=" + uuid.toString(),            0);
+
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?name=na",                  0);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?name=na_",                 0);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?name=na__",               45, -1);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?name=na___",               0);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?name=na%",                45, -1);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?name=name",               45, -1);
+
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?mnemonicequivalence=A__",  0);
+
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?mnemonic=A__",             0);
+
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?description=desc",         0);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?description=desc%",       35, -1);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?description=sc",           0);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?description=sc%",          0);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?description=%sc",          0);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?description=%sc%",        45, -1);
+            ITUtilStructureElement.assertRead("/DEVICEGROUP?description=description", 35, -1);
+
+            // children
+            //     /children/{type}/{uuid}
+            //     type, uuid, statuses, deleted, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            ITUtilStructureElement.assertRead("/children/DEVICEGROUP/" + uuid.toString(),             0);
+            ITUtilStructureElement.assertRead("/children/DISCIPLINE/"  + discipline2Uuid.toString(), 15, -1);
+
+            // mnemonic
+            //     /mnemonic/{mnemonic}
+            ITUtilStructureElement.assertRead("/mnemonic/A",        0);
+            ITUtilStructureElement.assertRead("/mnemonic/A__",      0);
+            ITUtilStructureElement.assertRead("/mnemonic/AG_",      0);
+            ITUtilStructureElement.assertRead("/mnemonic/AG1",      0);
+            ITUtilStructureElement.assertRead("/mnemonic/Di2",      1);
+
+            // mnemonic path
+            //     /mnemonicpath/{mnemonicpath}
+            ITUtilStructureElement.assertRead("/mnemonicpath/D",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/D%",  16, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/D__", 16, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Di_", 16, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Di2", 16);
+
+            // history
+            //     /history/{uuid}
+            ITUtilStructureElement.assertRead("/history/" + uuid.toString(),            1);
+            ITUtilStructureElement.assertRead("/history/" + discipline2Uuid.toString(), 1);
 
-            ITUtilStructureElement.assertExists(Type.DEVICEGROUP, "Di",  Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.DEVICEGROUP, "Di2", Boolean.TRUE);
         } catch (Exception e) {
             fail();
diff --git a/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java b/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
index c1e33320..4103702c 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
@@ -1789,6 +1789,10 @@ class StructuresDeviceTypeIT {
             // from first structure element
             assertNotNull(uuid);
 
+            // read & search
+            //     /{type}
+            //     type, statuses, deleted, uuid, parentuuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            //     combination
             ITUtilStructureElement.assertRead("/DEVICETYPE?mnemonic=A__",                                                  45);
             ITUtilStructureElement.assertRead("/DEVICETYPE?statuses=PENDING&mnemonic=A__",                                 10);
             ITUtilStructureElement.assertRead("/DEVICETYPE?statuses=APPROVED&mnemonic=A__",                                20);
@@ -1810,9 +1814,65 @@ class StructuresDeviceTypeIT {
             ITUtilStructureElement.assertRead("/DEVICETYPE?deleted=true&statuses=REJECTED&mnemonic=A__",                    5);
             ITUtilStructureElement.assertRead("/DEVICETYPE?deleted=true&statuses=PENDING&statuses=APPROVED&mnemonic=A__",  10);
 
-            ITUtilStructureElement.assertRead("/children/DEVICETYPE/" + uuid.toString(),             0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?uuid=" + disciplineUuid.toString(),         0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?uuid=" + deviceGroupUuid.toString(),        0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?uuid=" + uuid.toString(),                   1);
+
+            ITUtilStructureElement.assertRead("/DEVICETYPE?parentuuid=" + disciplineUuid.toString(),   0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?parentuuid=" + deviceGroupUuid.toString(), 45, -1);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?parentuuid=" + uuid.toString(),             0);
+
+            ITUtilStructureElement.assertRead("/DEVICETYPE?name=na",                  0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?name=na_",                 0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?name=na__",               45, -1);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?name=na___",               0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?name=na%",                45, -1);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?name=name",               45, -1);
+
+            ITUtilStructureElement.assertRead("/DEVICETYPE?mnemonicequivalence=A__", 45, -1);
+
+            ITUtilStructureElement.assertRead("/DEVICETYPE?mnemonicepath=A__",       45, -1);
+
+            ITUtilStructureElement.assertRead("/DEVICETYPE?description=desc",         0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?description=desc%",       35, -1);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?description=sc",           0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?description=sc%",          0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?description=%sc",          0);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?description=%sc%",        45, -1);
+            ITUtilStructureElement.assertRead("/DEVICETYPE?description=description", 35, -1);
+
+            // children
+            //     /children/{type}/{uuid}
+            //     type, uuid, statuses, deleted, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            ITUtilStructureElement.assertRead("/children/DEVICETYPE/"  + uuid.toString(),            0);
             ITUtilStructureElement.assertRead("/children/DEVICEGROUP/" + deviceGroupUuid.toString(), 1, -1);
-            ITUtilStructureElement.assertRead("/children/DISCIPLINE/" + disciplineUuid.toString(),   1, -1);
+            ITUtilStructureElement.assertRead("/children/DISCIPLINE/"  + disciplineUuid.toString(),  1, -1);
+
+            // mnemonic
+            //     /mnemonic/{mnemonic}
+            ITUtilStructureElement.assertRead("/mnemonic/A",           0);
+            ITUtilStructureElement.assertRead("/mnemonic/A__",        15, -1);
+            ITUtilStructureElement.assertRead("/mnemonic/AG_",         5);
+            ITUtilStructureElement.assertRead("/mnemonic/AG1",         1);
+            ITUtilStructureElement.assertRead("/mnemonic/Di",          1);
+
+            // mnemonic path
+            //     /mnemonicpath/{mnemonicpath}
+            ITUtilStructureElement.assertRead("/mnemonicpath/A",       0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/A__",     0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG_",     0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG1",     0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Di-A%",  15, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Di-A",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Di-A__", 15, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Di-AG_",  5);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Di-AG1",  1);
+
+            // history
+            //     /history/{uuid}
+            ITUtilStructureElement.assertRead("/history/" + uuid.toString(),            1);
+            ITUtilStructureElement.assertRead("/history/" + deviceGroupUuid.toString(), 1);
+            ITUtilStructureElement.assertRead("/history/" + disciplineUuid.toString(),  1);
 
             ITUtilStructureElement.assertExists(Type.DEVICETYPE, "Di-AA1", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.DEVICETYPE, "Di-AA2", Boolean.TRUE);
diff --git a/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java b/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
index 496cbd5a..f18cf5d4 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
@@ -1694,6 +1694,10 @@ class StructuresDisciplineIT {
             // from first structure element
             assertNotNull(uuid);
 
+            // read & search
+            //     /{type}
+            //     type, statuses, deleted, uuid, parentuuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            //     combination
             ITUtilStructureElement.assertRead("/DISCIPLINE?mnemonic=A__",                                                  45);
             ITUtilStructureElement.assertRead("/DISCIPLINE?statuses=PENDING&mnemonic=A__",                                 10);
             ITUtilStructureElement.assertRead("/DISCIPLINE?statuses=APPROVED&mnemonic=A__",                                20);
@@ -1715,8 +1719,52 @@ class StructuresDisciplineIT {
             ITUtilStructureElement.assertRead("/DISCIPLINE?deleted=true&statuses=REJECTED&mnemonic=A__",                    5);
             ITUtilStructureElement.assertRead("/DISCIPLINE?deleted=true&statuses=PENDING&statuses=APPROVED&mnemonic=A__",  10);
 
+            ITUtilStructureElement.assertRead("/DISCIPLINE?uuid=" + uuid.toString(),        1);
+
+            ITUtilStructureElement.assertRead("/DISCIPLINE?parentuuid=" + uuid.toString(),  0);
+
+            ITUtilStructureElement.assertRead("/DISCIPLINE?name=na",                        0);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?name=na_",                       0);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?name=na__",                     45, -1);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?name=na___",                     0);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?name=na%",                      45, -1);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?name=name",                     45, -1);
+
+            ITUtilStructureElement.assertRead("/DISCIPLINE?mnemonicequivalence=A__",       45, -1);
+
+            ITUtilStructureElement.assertRead("/DISCIPLINE?mnemonicepath=A__",             45, -1);
+
+            ITUtilStructureElement.assertRead("/DISCIPLINE?description=desc",               0);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?description=desc%",             35, -1);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?description=sc",                 0);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?description=sc%",                0);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?description=%sc",                0);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?description=%sc%",              45, -1);
+            ITUtilStructureElement.assertRead("/DISCIPLINE?description=description",       35, -1);
+
+            // children
+            //     /children/{type}/{uuid}
+            //     type, uuid, statuses, deleted, name, mnemonic, mnemonicequivalence, mnemonicpath, description
             ITUtilStructureElement.assertRead("/children/DISCIPLINE/" + uuid.toString(), 0);
 
+            // mnemonic
+            //     /mnemonic/{mnemonic}
+            ITUtilStructureElement.assertRead("/mnemonic/A",        0);
+            ITUtilStructureElement.assertRead("/mnemonic/A__",     15, -1);
+            ITUtilStructureElement.assertRead("/mnemonic/AG_",      5);
+            ITUtilStructureElement.assertRead("/mnemonic/AG1",      1);
+
+            // mnemonic path
+            //     /mnemonicpath/{mnemonicpath}
+            ITUtilStructureElement.assertRead("/mnemonicpath/A",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/A__", 15, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG_",  5);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG1",  1);
+
+            // history
+            //     /history/{uuid}
+            ITUtilStructureElement.assertRead("/history/" + uuid.toString(),  1);
+
             ITUtilStructureElement.assertExists(Type.DISCIPLINE, "AA1", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.DISCIPLINE, "AA2", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.DISCIPLINE, "AA3", Boolean.TRUE);
diff --git a/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java b/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
index 0cf4086c..142a8170 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
@@ -1841,6 +1841,10 @@ class StructuresSubsystemIT {
             // from first structure element
             assertNotNull(uuid);
 
+            // read & search
+            //     /{type}
+            //     type, statuses, deleted, uuid, parentuuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            //     combination
             ITUtilStructureElement.assertRead("/SUBSYSTEM?mnemonic=A__",                                                  45);
             ITUtilStructureElement.assertRead("/SUBSYSTEM?statuses=PENDING&mnemonic=A__",                                 10);
             ITUtilStructureElement.assertRead("/SUBSYSTEM?statuses=APPROVED&mnemonic=A__",                                20);
@@ -1862,10 +1866,82 @@ class StructuresSubsystemIT {
             ITUtilStructureElement.assertRead("/SUBSYSTEM?deleted=true&statuses=REJECTED&mnemonic=A__",                    5);
             ITUtilStructureElement.assertRead("/SUBSYSTEM?deleted=true&statuses=PENDING&statuses=APPROVED&mnemonic=A__",  10);
 
-            ITUtilStructureElement.assertRead("/children/SUBSYSTEM/" + uuid.toString(),              0);
-            ITUtilStructureElement.assertRead("/children/SYSTEM/" + systemUuid.toString(),           1, -1);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?uuid=" + systemGroupUuid.toString(),        0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?uuid=" + systemUuid.toString(),             0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?uuid=" + uuid.toString(),                   1);
+
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?parentuuid=" + systemGroupUuid.toString(),  0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?parentuuid=" + systemUuid.toString(),      45, -1);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?parentuuid=" + uuid.toString(),             0);
+
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?name=na",                  0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?name=na_",                 0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?name=na__",               45, -1);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?name=na___",               0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?name=na%",                45, -1);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?name=name",               45, -1);
+
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?mnemonicequivalence=A__", 45, -1);
+
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?mnemonicepath=A__",       45, -1);
+
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?description=desc",         0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?description=desc%",       35, -1);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?description=sc",           0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?description=sc%",          0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?description=%sc",          0);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?description=%sc%",        45, -1);
+            ITUtilStructureElement.assertRead("/SUBSYSTEM?description=description", 35, -1);
+
+            // children
+            //     /children/{type}/{uuid}
+            //     type, uuid, statuses, deleted, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            ITUtilStructureElement.assertRead("/children/SUBSYSTEM/"   + uuid.toString(),            0);
+            ITUtilStructureElement.assertRead("/children/SUBSYSTEM/"   + systemUuid.toString(),      0);
+            ITUtilStructureElement.assertRead("/children/SUBSYSTEM/"   + systemGroupUuid.toString(), 0);
+            ITUtilStructureElement.assertRead("/children/SYSTEM/"      + uuid.toString(),            0);
+            ITUtilStructureElement.assertRead("/children/SYSTEM/"      + systemUuid.toString(),      1, -1);
+            ITUtilStructureElement.assertRead("/children/SYSTEM/"      + systemGroupUuid.toString(), 0);
+            ITUtilStructureElement.assertRead("/children/SYSTEMGROUP/" + uuid.toString(),            0);
+            ITUtilStructureElement.assertRead("/children/SYSTEMGROUP/" + systemUuid.toString(),      0);
             ITUtilStructureElement.assertRead("/children/SYSTEMGROUP/" + systemGroupUuid.toString(), 1, -1);
 
+            // mnemonic
+            //     /mnemonic/{mnemonic}
+            ITUtilStructureElement.assertRead("/mnemonic/A",             0);
+            ITUtilStructureElement.assertRead("/mnemonic/A__",          15, -1);
+            ITUtilStructureElement.assertRead("/mnemonic/AG_",           5);
+            ITUtilStructureElement.assertRead("/mnemonic/AG1",           1);
+            ITUtilStructureElement.assertRead("/mnemonic/Sg",            1);
+
+            // mnemonic path
+            //     /mnemonicpath/{mnemonicpath}
+            ITUtilStructureElement.assertRead("/mnemonicpath/A",         0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/A__",       0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG_",       0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG1",       0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sys-A%",   15, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sys-A",     0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sys-A__",  15, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sys-AG_",   5);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sys-AG1",   1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-A%",     0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-A",      0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-A__",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-AG_",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-AG1",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-Sys%",   0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-Sys",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-Sys__",  0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-Sys_",   0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-Sys",    0);
+
+            // history
+            //     /history/{uuid}
+            ITUtilStructureElement.assertRead("/history/" + uuid.toString(),            1);
+            ITUtilStructureElement.assertRead("/history/" + systemUuid.toString(),      1);
+            ITUtilStructureElement.assertRead("/history/" + systemGroupUuid.toString(), 1);
+
             ITUtilStructureElement.assertExists(Type.SUBSYSTEM, "Sys-AA1", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.SUBSYSTEM, "Sys-AA2", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.SUBSYSTEM, "Sys-AA3", Boolean.TRUE);
diff --git a/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java b/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
index 79c37105..543d8afb 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
@@ -1738,6 +1738,10 @@ class StructuresSystemGroupIT {
             // from first structure element
             assertNotNull(uuid);
 
+            // read & search
+            //     /{type}
+            //     type, statuses, deleted, uuid, parentuuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            //     combination
             ITUtilStructureElement.assertRead("/SYSTEMGROUP?mnemonic=A__",                                                  45);
             ITUtilStructureElement.assertRead("/SYSTEMGROUP?statuses=PENDING&mnemonic=A__",                                 10);
             ITUtilStructureElement.assertRead("/SYSTEMGROUP?statuses=APPROVED&mnemonic=A__",                                20);
@@ -1759,8 +1763,52 @@ class StructuresSystemGroupIT {
             ITUtilStructureElement.assertRead("/SYSTEMGROUP?deleted=true&statuses=REJECTED&mnemonic=A__",                    5);
             ITUtilStructureElement.assertRead("/SYSTEMGROUP?deleted=true&statuses=PENDING&statuses=APPROVED&mnemonic=A__",  10);
 
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?uuid=" + uuid.toString(),        1);
+
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?parentuuid=" + uuid.toString(),  0);
+
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?name=na",                        0);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?name=na_",                       0);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?name=na__",                     45, -1);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?name=na___",                     0);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?name=na%",                      45, -1);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?name=name",                     45, -1);
+
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?mnemonicequivalence=A__",       45, -1);
+
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?mnemonicepath=A__",             45, -1);
+
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?description=desc",               0);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?description=desc%",             35, -1);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?description=sc",                 0);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?description=sc%",                0);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?description=%sc",                0);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?description=%sc%",              45, -1);
+            ITUtilStructureElement.assertRead("/SYSTEMGROUP?description=description",       35, -1);
+
+            // children
+            //     /children/{type}/{uuid}
+            //     type, uuid, statuses, deleted, name, mnemonic, mnemonicequivalence, mnemonicpath, description
             ITUtilStructureElement.assertRead("/children/SYSTEMGROUP/" + uuid.toString(), 0);
 
+            // mnemonic
+            //     /mnemonic/{mnemonic}
+            ITUtilStructureElement.assertRead("/mnemonic/A",        0);
+            ITUtilStructureElement.assertRead("/mnemonic/A__",     15, -1);
+            ITUtilStructureElement.assertRead("/mnemonic/AG_",      5);
+            ITUtilStructureElement.assertRead("/mnemonic/AG1",      1);
+
+            // mnemonic path
+            //     /mnemonicpath/{mnemonicpath}
+            ITUtilStructureElement.assertRead("/mnemonicpath/A",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/A__", 15, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG_",  5);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG1",  1);
+
+            // history
+            //     /history/{uuid}
+            ITUtilStructureElement.assertRead("/history/" + uuid.toString(), 1);
+
             ITUtilStructureElement.assertExists(Type.SYSTEMGROUP, "AA1", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.SYSTEMGROUP, "AA2", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.SYSTEMGROUP, "AA3", Boolean.TRUE);
diff --git a/src/test/java/org/openepics/names/docker/StructuresSystemIT.java b/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
index 97190d68..0ef774dd 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
@@ -1774,6 +1774,10 @@ class StructuresSystemIT {
             // from first structure element
             assertNotNull(uuid);
 
+            // read & search
+            //     /{type}
+            //     type, statuses, deleted, uuid, parentuuid, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            //     combination
             ITUtilStructureElement.assertRead("/SYSTEM?mnemonic=A__",                                                  45);
             ITUtilStructureElement.assertRead("/SYSTEM?statuses=PENDING&mnemonic=A__",                                 10);
             ITUtilStructureElement.assertRead("/SYSTEM?statuses=APPROVED&mnemonic=A__",                                20);
@@ -1795,9 +1799,64 @@ class StructuresSystemIT {
             ITUtilStructureElement.assertRead("/SYSTEM?deleted=true&statuses=REJECTED&mnemonic=A__",                    5);
             ITUtilStructureElement.assertRead("/SYSTEM?deleted=true&statuses=PENDING&statuses=APPROVED&mnemonic=A__",  10);
 
-            ITUtilStructureElement.assertRead("/children/SYSTEM/" + uuid.toString(),                 0);
+            ITUtilStructureElement.assertRead("/SYSTEM?uuid=" + systemGroupUuid.toString(),        0);
+            ITUtilStructureElement.assertRead("/SYSTEM?uuid=" + uuid.toString(),                   1);
+
+            ITUtilStructureElement.assertRead("/SYSTEM?parentuuid=" + systemGroupUuid.toString(), 45, -1);
+            ITUtilStructureElement.assertRead("/SYSTEM?parentuuid=" + uuid.toString(),             0);
+
+            ITUtilStructureElement.assertRead("/SYSTEM?name=na",                        0);
+            ITUtilStructureElement.assertRead("/SYSTEM?name=na_",                       0);
+            ITUtilStructureElement.assertRead("/SYSTEM?name=na__",                     45, -1);
+            ITUtilStructureElement.assertRead("/SYSTEM?name=na___",                     0);
+            ITUtilStructureElement.assertRead("/SYSTEM?name=na%",                      45, -1);
+            ITUtilStructureElement.assertRead("/SYSTEM?name=name",                     45, -1);
+
+            ITUtilStructureElement.assertRead("/SYSTEM?mnemonicequivalence=A__",       45, -1);
+
+            ITUtilStructureElement.assertRead("/SYSTEM?mnemonicepath=A__",             45, -1);
+
+            ITUtilStructureElement.assertRead("/SYSTEM?description=desc",               0);
+            ITUtilStructureElement.assertRead("/SYSTEM?description=desc%",             35, -1);
+            ITUtilStructureElement.assertRead("/SYSTEM?description=sc",                 0);
+            ITUtilStructureElement.assertRead("/SYSTEM?description=sc%",                0);
+            ITUtilStructureElement.assertRead("/SYSTEM?description=%sc",                0);
+            ITUtilStructureElement.assertRead("/SYSTEM?description=%sc%",              45, -1);
+            ITUtilStructureElement.assertRead("/SYSTEM?description=description",       35, -1);
+
+            // children
+            //     /children/{type}/{uuid}
+            //     type, uuid, statuses, deleted, name, mnemonic, mnemonicequivalence, mnemonicpath, description
+            ITUtilStructureElement.assertRead("/children/SYSTEM/"      + uuid.toString(),            0);
+            ITUtilStructureElement.assertRead("/children/SYSTEM/"      + systemGroupUuid.toString(), 0);
+            ITUtilStructureElement.assertRead("/children/SYSTEMGROUP/" + uuid.toString(),            0);
             ITUtilStructureElement.assertRead("/children/SYSTEMGROUP/" + systemGroupUuid.toString(), 1, -1);
 
+            // mnemonic
+            //     /mnemonic/{mnemonic}
+            ITUtilStructureElement.assertRead("/mnemonic/A",           0);
+            ITUtilStructureElement.assertRead("/mnemonic/A__",        15, -1);
+            ITUtilStructureElement.assertRead("/mnemonic/AG_",         5);
+            ITUtilStructureElement.assertRead("/mnemonic/AG1",         1);
+            ITUtilStructureElement.assertRead("/mnemonic/Sg",          1);
+
+            // mnemonic path
+            //     /mnemonicpath/{mnemonicpath}
+            ITUtilStructureElement.assertRead("/mnemonicpath/A",       0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/A__",    15, -1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG_",     5);
+            ITUtilStructureElement.assertRead("/mnemonicpath/AG1",     1);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-A%",   0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-A",    0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-A__",  0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-AG_",  0);
+            ITUtilStructureElement.assertRead("/mnemonicpath/Sg-AG1",  0);
+
+            // history
+            //     /history/{uuid}
+            ITUtilStructureElement.assertRead("/history/" + uuid.toString(),            1);
+            ITUtilStructureElement.assertRead("/history/" + systemGroupUuid.toString(), 1);
+
             ITUtilStructureElement.assertExists(Type.SYSTEM, "AA1", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.SYSTEM, "AA2", Boolean.TRUE);
             ITUtilStructureElement.assertExists(Type.SYSTEM, "AA3", Boolean.TRUE);
diff --git a/src/test/java/org/openepics/names/util/EncodingUtilityTest.java b/src/test/java/org/openepics/names/util/EncodingUtilityTest.java
new file mode 100644
index 00000000..247c5a2a
--- /dev/null
+++ b/src/test/java/org/openepics/names/util/EncodingUtilityTest.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2018 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.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Purpose to test EncodingUtility class.
+ *
+ * @author Lars Johansson
+ */
+public class EncodingUtilityTest {
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringNull() {
+        String s = null;
+        assertThrows(NullPointerException.class, () -> { EncodingUtility.encode(s); });
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringEmpty() {
+        String s = "";
+        assertEquals(s, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringPercent() {
+        String s = "%";
+        String expected = "%25";
+        assertEquals(expected, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringPlus() {
+        String s = "+";
+        String expected = "%2B";
+        assertEquals(expected, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringUnderscore() {
+        String s = "_";
+        String expected ="_";
+        assertEquals(expected, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringWhitespace() {
+        String s = " ";
+        String expected ="+";
+        assertEquals(expected, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringNumbers() {
+        String s = "12345678";
+        assertEquals(s, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringLetters() {
+        String s = "abcdefgh";
+        assertEquals(s, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringLettersPlus() {
+        String s = "abc+efgh";
+        String expected = "abc%2Befgh";
+        assertEquals(expected, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringLettersWhitespace() {
+        String s = "abcd fgh";
+        String expected = "abcd+fgh";
+        assertEquals(expected, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testEncodeStringLettersPlusWhitespace() {
+        String s = "ab de+gh";
+        String expected = "ab+de%2Bgh";
+        assertEquals(expected, EncodingUtility.encode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringNull() {
+        String s = null;
+        assertThrows(NullPointerException.class, () -> { EncodingUtility.decode(s); });
+
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringEmpty() {
+        String s = "";
+        assertEquals(s, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringPercent() {
+        String s = "%25";
+        String expected = "%";
+        assertEquals(expected, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringPlus() {
+        String s = "%2B";
+        String expected = "+";
+        assertEquals(expected, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringUnderscore() {
+        String s = "_";
+        String expected = "_";
+        assertEquals(expected, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringWhitespace() {
+        String s = "+";
+        String expected = " ";
+        assertEquals(expected, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringNumbers() {
+        String s = "12345678";
+        assertEquals(s, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringLetters() {
+        String s = "abcdefgh";
+        assertEquals(s, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringLettersPlus() {
+        String s = "abc%2Befgh";
+        String expected = "abc+efgh";
+        assertEquals(expected, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringLettersWhitespace() {
+        String s = "abcd+fgh";
+        String expected = "abcd fgh";
+        assertEquals(expected, EncodingUtility.decode(s));
+    }
+
+    /**
+     * Test for encoding a string.
+     */
+    @Test
+    void testDecodeStringLettersPlusWhitespace() {
+        String s = "ab+de%2Bgh";
+        String expected = "ab de+gh";
+        assertEquals(expected, EncodingUtility.decode(s));
+    }
+
+}
diff --git a/src/test/java/org/openepics/names/util/URLUtilityTest.java b/src/test/java/org/openepics/names/util/URLUtilityTest.java
new file mode 100644
index 00000000..c835be49
--- /dev/null
+++ b/src/test/java/org/openepics/names/util/URLUtilityTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2018 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 org.junit.jupiter.api.Test;
+
+/**
+ * Purpose to test URLUtility class.
+ *
+ * @author Lars Johansson
+ */
+public class URLUtilityTest {
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLNull() {
+        String url = null;
+        assertEquals(url, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLEmpty() {
+        String url = "";
+        assertEquals(url, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLWhitespace() {
+        String url = " ";
+        String expected = "+";
+        assertEquals(expected, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLString() {
+        String url = "abcd1234";
+        assertEquals(url, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPath() {
+        String url = "abcd.xhtml";
+        assertEquals(url, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQuery() {
+        String url = "abcd.xhtml?efgh";
+        assertEquals(url, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryPercent() {
+        String url = "/abcd.xhtml?uvwx-0%";
+        String expected = "/abcd.xhtml?uvwx-0%25";
+        assertEquals(expected, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryPlus() {
+        String url = "abcd.xhtml?efg+h";
+        String expected = "abcd.xhtml?efg%2Bh";
+        assertEquals(expected, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryWhitespace() {
+        String url = "abcd.xhtml?ef gh";
+        String expected = "abcd.xhtml?ef+gh";
+        assertEquals(expected, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryAttributeValue1Pair() {
+        String url = "abcd.xhtml?efgh=ijkl";
+        assertEquals(url, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryAttributeValue1PairEmpty() {
+        String url = "abcd.xhtml?efgh=";
+        assertEquals(url, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryAttributeValue1PairComplex() {
+        String url = "abcd.xhtml?efgh=ijkl mnop+qrst+ uvwx";
+        String expected = "abcd.xhtml?efgh=ijkl+mnop%2Bqrst%2B+uvwx";
+        assertEquals(expected, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryAttributeValue2Pairs() {
+        String url = "abcd.xhtml?efgh=ijkl&mnop=qrst";
+        assertEquals(url, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryAttributeValue2PairsComplex() {
+        String url = "abcd.xhtml?efgh=i+kl&mnop=qr t";
+        String expected = "abcd.xhtml?efgh=i%2Bkl&mnop=qr+t";
+        assertEquals(expected, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryAttributeValue3PairsComplex() {
+        String url = "abcd.xhtml?efgh&uvwx=yzabc  def++ghijklm+ nop&abcdefgh=";
+        String expected = "abcd.xhtml?efgh&uvwx=yzabc++def%2B%2Bghijklm%2B+nop&abcdefgh=";
+        assertEquals(expected, URLUtility.encodeURL(url));
+    }
+
+    /**
+     * Test for encoding a URL.
+     */
+    @Test
+    void testEncodeURLPathQueryIpPortPercent() {
+        String url = "http://127.0.0.1:8080/a/b/c/d/e/f/RFQ-010:EMR-FS-0%";
+        String expected = "http://127.0.0.1:8080/a/b/c/d/e/f/RFQ-010%3AEMR-FS-0%25";
+        assertEquals(expected, URLUtility.encodeURL(url));
+    }
+
+}
-- 
GitLab